搜索加大数的周赛,结果不是很让人满意啊~我这队长水平一般,只能提供环境希望他们多努力努力了~
把几道不算水的题拿出来解析一下~
A Zipper
一道算搜索的递归题,题目大意是,给三个字符串,问第三个是否是前两个字符串嵌套成的.题目叫拉链~基本就那意思了.
基本思想就是递归对比,有几个要注意的地方:
1. 要从后往前比,
2. 当a[i]==b[j]时要挨个试.
源代码:
#include <myhead>
const int N=500;
char a[N],b[N],c[N];
int dfs(int x,int y,int z) {
if(z<0) {
return true;
}
if(x>=0&&a[x]==c[z]) {
if(dfs(x-1,y,z-1))
return true;
}
if(y>=0&&b[y]==c[z]) {
if(dfs(x,y-1,z-1))
return true;
}
return false;
}
int main() {
int t,m=1;
scanf("%d",&t);
while(t--) {
scanf("%s%s%s",a,b,c);
if(dfs(strlen(a)-1,strlen(b)-1,strlen(c)-1)) {
printf("Data set %d: yes\n",m);
} else {
printf("Data set %d: no\n",m);
}
m=m+1;
}
return 0;
}
还有一种做法是动态规划:
状态数组为 bool dp[i][j] , 也就是c[i+j]由a的前i个和b的前j个组成.
状态转移方程为:
dp[0][0] = 1;
dp[i][0]=dp[i-1][0]&&a[i-1]==c[i-1]; i>0
dp[0][j]=dp[0][j-1]&&b[j-1]==c[j-1]; j>0
dp[i][j] = (dp[i-1][j]&&a[i]==c[i+j]) || (dp[i][j-1]&&b[j]==c[i+j]); i,j>0
源代码:
#include <myhead.h>
const int N=210;
int main()
{
int t,m=1;
bool dp[N][N];
string a,b,c;
cin>>t;
while(t--) {
memset(dp,0,sizeof(dp));
cin>>a>>b>>c;
dp[0][0]=1;
for(size_t i=1;i<=a.size();++i) {
dp[i][0]=(dp[i-1][0]&&a[i-1]==c[i-1]);
}
for(size_t j=1;j<=b.size();++j) {
dp[0][j]=(dp[0][j-1]&&b[j-1]==c[j-1]);
}
for(size_t i=1;i<=a.size();++i) {
for(size_t j=1;j<=b.size();++j) {
dp[i][j]=(dp[i-1][j]&&a[i-1]==c[i+j-1]) || (dp[i][j-1]&&b[j-1]==c[i+j-1]);
}
}
if(dp[a.size()][b.size()]) {
printf("Data set %d: yes\n",m);
} else {
printf("Data set %d: no\n",m);
}
m=m+1;
}
return 0;
}
B Flip Game
http://blog.csdn.net/gj_fb_dabai/article/details/8742470
直接发链接了~
E Square
和 http://poj.grids.cn/practice/1011/ 差不多~题目大意:
给n个数 ,问这n个数能不能组成一个正方形.
解题思想:
一道普通的回溯法dfs, 状态组为(剩余长度num,已经分了几堆m,总共的剩余长度ssum,当前搜到的位置s);初始状态为 (sum/4,1,sum,0).
直接搜索当然会超时,需要有几点注意.
1.当m==3时即可退出,因为若所有数的合sum%4==0 最后剩余的一组一定满足条件.
2.对数组按从大到小顺序排序,这样只要搜索比当前值大的值即可.
状态转移方程为:
num<0 -> return false;
num==0
-> m==3 -> return true;
-> ssum%(4-m)==0 -> return (sum/4,m+1,ssum,0);
else -> return flase;
num!=0 -> (num-a[i],m,ssum-a[i],i+1);
源代码:
#include <myhead.h>
const int N=30;
int n,sum;
bool _hash[N];
int dis[N];
void init() {
sum=0;
memset(_hash,0,sizeof(_hash));
scanf("%d",&n);
for(int i=0;i<n;++i) {
scanf("%d",&dis[i]);
sum+=dis[i];
}
dis[n]=sum;
sort(dis,dis+n);
}
bool dfs(int num,int m,int ssum,int s) {
if(num==0) {
if(m==3) {
return true;
} else {
return dfs(sum/4,m+1,ssum,0);
}
}
for(int i=s;i<n;++i) {
if(!_hash[i]) {
_hash[i]=true;
if(dfs(num-dis[i],m,ssum-dis[i],i+1)) {
return true;
}
_hash[i]=false;
}
}
return false;
}
int main()
{
int t;
scanf("%d",&t);
while(t--) {
init();
if(sum%4==0&&dfs(sum/4,1,sum,0)) {
puts("yes");
} else {
puts("no");
}
}
return 0;
}
G:集合加法
知道题本不是值得写的题,但是大一的童鞋们竟然全用双for循环写的,就现写了一个基数排序,然他们脑袋灵活点~直接源代码了:
#include <myhead.h>
const int N=10010;
int main()
{
int t;
scanf("%d",&t);
while(t--) {
int s;
scanf("%d",&s);
int a_size,b_size,t;
int a[N],b[N];
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
scanf("%d",&a_size);
for(int i=0;i<a_size;++i) {
scanf("%d",&t);
a[t]++;
}
scanf("%d",&b_size);
for(int i=0;i<b_size;++i) {
scanf("%d",&t);
b[t]++;
}
int sum=0;
for(int i=1;i<s;++i) {
sum=sum+(a[i]*b[s-i]);
}
printf("%d\n",sum);
}
return 0;
}
J:HTML
一道模拟题,也没什么意思,全场一看那么长都没写,我就写了~根据要求 ,<br>换行, <hr>换行输出80个'-', 每80个字符换行一次.
源代码:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string szWord;
int nCount = 0;
int i;
while (cin >> szWord)
{
if (szWord == "<hr>")
{
if (nCount != 0)
cout << endl;
for (i=0; i<80; i++)
cout << "-";
cout << endl;
nCount = 0;
}
else if (szWord == "<br>")
{
cout << endl;
nCount = 0;
}
else
{
if (nCount + szWord.size() + (nCount == 0 ? 0 : 1) > 80)
{
cout << endl;
cout << szWord;
nCount = szWord.size();
}
else
{
if (nCount != 0)
cout << " ";
cout << szWord;
nCount += szWord.size() + 1;
}
}
}
cout << endl;
return 0;
}