UVa 129 Krypton Factor
注意输出格式,比较坑爹。
每次要进行处理去掉容易的串,统计困难串的个数。
#include<iostream> #include<vector> #include<cmath> #include<map> #include<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include<string> #define INF 1000000000LL #define ll long long using namespace std; char str[100]; int cnt,K,L; bool check(int len) { int l=strlen(str); if(l==0||l==1) return false; for(int i=1; i<=len/2; ++i) { bool ok=true; for(int j=0; j<i&&ok; ++j) { if(str[len-1-j]!=str[len-1-i-j]) ok=false; } if(ok) return true; } return false; } void dfs(int pos) { if(cnt>=K) return ; else { for(int i=0; i<L; ++i) { str[pos]=‘A‘+i; str[pos+1]=0; if(!check(pos+1)) cnt++; else continue ; dfs(pos+1); if(cnt>=K) return ; } } } int main() { while(scanf("%d%d",&K,&L)!=EOF) { if(!K&&!L) break; cnt=0; dfs(0); int L=strlen(str); for(int i=0; str[i]; ++i) { if(i&&i%4==0&&i%64) putchar(‘ ‘); putchar(str[i]); if((i+1)%64==0) putchar(‘\n‘); } if(L%64) putchar(‘\n‘); printf("%d\n",L); } return 0; }
SPOJ COMCB 1003
注意棋盘方格总数不会超过26。所以可以尝试dfs回溯寻找最优解。
怎么找字典序最小的,这个把棋盘画出来,然后指定一下每次跳的方向的顺序就行。如果第一个跳完全部棋盘的就是最优解。
这里要求输出最优解,每个位置是二维的,可以把它们压缩成一维,开一个数组,下标存第几步,内容存位置,这样就方便储存了。
实际上可行解并不多,可以打表。
HDU 4848 Wow! Such Conquering!
首先用fylod求最短路,然后搜索。时间复杂度大约是30!。肯定要剪枝。
有两个剪枝,一个是如果当前时刻有星球永远无法到达,则return,另一个是如果到该星球以后的时间花费比当前最优解要小则剪枝。这样就能过了。
#include <iostream> #include <string> #include <cstdio> #include <cstring> #include <algorithm> #define inf 100000000 using namespace std; int dist[35][35],tim[35]; int n; int ans; bool vis[35]; void dfs(int now,int rest,int all,int sum) { if(all>=ans) return ; if(rest==0) { ans=min(ans,all); return ; } for(int i=1; i<n; ++i) if((!vis[i])&&(sum+dist[now][i]>tim[i])) return; for(int i=1; i<n; ++i) { if(!vis[i]) { int time=sum+dist[now][i]; if(time<=tim[i]) { if(ans<=all+rest*time) continue; vis[i]=true; dfs(i,rest-1,all+time,time); vis[i]=false; } } } } int main() { while(scanf("%d",&n)!=EOF) { for(int i=0; i<n; ++i) for(int j=0; j<n; ++j) { scanf("%d",&dist[i][j]); } for(int k=0; k<n; ++k) for(int i=0; i<n; ++i) for(int j=0; j<n; ++j) dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]); for(int i=1; i<n; ++i) { scanf("%d",&tim[i]); } ans=inf; memset(vis,0,sizeof(vis)); vis[0]=true; dfs(0,n-1,0,0); if(ans==inf) puts("-1"); else printf("%d\n",ans); } return 0; }
SGU 125 Shtirlits
给一个矩阵B,每个元素B[i][j]表示A[i][j]上下左右四周有多少个数大于自身。输出一个可能的矩阵A。
由于n<=3,完全可以暴力搜索解决。但是9^9肯定会超时的,考虑剪枝。对于每个A[i][j]枚举可能的元素,当枚举到第二行以上的时候,该元素上面的一个元素四周的元素都已经确定了,可以判断是否满足题意,不满足则剪枝。当枚举到最后一行的时候,还可以判断左边的元素是否满足题意。当所有元素都枚举完毕,要进行一次全体的判断,如果符合就是答案。
之前想到一个剪枝,以为每次枚举A[i][j],可以从0枚举到9-B[i][j]。其实这是不对的,因为比A[i][j]大的元素可能是相同的。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int B[4][4]; int A[4][4]; int n; bool judge(int x,int y) { return 0<=x&&x<n&&0<=y&&y<n; } const int Move[4][2]= {{-1,0},{0,-1},{1,0},{0,1}}; bool check(int x,int y) { int cnt=0; for(int i=0; i<4; ++i) { int nx=x+Move[i][0],ny=y+Move[i][1]; if(judge(nx,ny)) { if(A[x][y]<A[nx][ny]) cnt++; } } return cnt==B[x][y]; } bool dfs(int cur) { if(cur==n*n) { for(int i=0;i<n;++i) for(int j=0;j<n;++j) if(!check(i,j)) return false; return true; } const int x=cur/n,y=cur%n; for(int i=0; i<=9; ++i) { A[x][y]=i; if((x>=1&&!check(x-1,y))||(x==n-1&&y>=1&&!check(x,y-1))) continue; if(dfs(cur+1)) return true; } return false; } int main() { while(scanf("%d",&n)!=EOF) { for(int i=0; i<n; ++i) for(int j=0; j<n; ++j) scanf("%d",&B[i][j]); if(!dfs(0)) puts("NO SOLUTION"); else { for(int i=0; i<n; ++i) { for(int j=0; j<n; ++j) if(!j) printf("%d",A[i][j]); else printf(" %d",A[i][j]); printf("\n"); } } } return 0; }
时间: 2024-10-06 19:11:59