随笔分类 - ACM题解
摘要:题目大意:给定一组单词(均为小写英文字母),每个单词表示能将其首字母变成尾字母,例如"go"表示能将'g'变成'o',问同过给定的单词能否将'b'变成'm'。分析:先建立有向图,然后对图进行DFS。View Code 1 #include <stdio.h> 2 #include <string.h> 3 #define N 60000000 4 char s[N],vis[26]; 5 bool g[26][26]; 6 bool read_case() 7 { 8 int n; 9
阅读全文
摘要:经典的DFS,素数环问题。题目大意:将从1开始的前n个自然数排成一个圈,使得任意相邻的两个数的和是素数。给定n,按字典序打印结果。View Code 1 #include <stdio.h> 2 #include <string.h> 3 #define N 20 4 int a[N],n,cnt; 5 char is_p[40],vis[N]; 6 void init() 7 { 8 memset(is_p,0,sizeof(is_p)); 9 is_p[2]=1;10 is_p[3]=1;11 is_p[5]=1;12 is_p[7]=1;13 is_p[11]=.
阅读全文
摘要:BFS题,走三维迷宫。View Code 1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 #define N 50 5 using namespace std; 6 typedef struct node 7 { 8 int x,y,z; 9 }node;10 queue<node> Q;11 node cur,next;12 int dx[6]={1,-1,0,0,0,0};13 int dy[6]={0,0,1,-1,0,0};14 int dz[6]={0,0,
阅读全文
摘要:BFS题,数学模型如下:对于一个01序列(长度小于20),定义翻转操作为:选定序列中的一位,将其取反,并将其左右相邻的位(如果存在)取反,现给定一个初始序列,求最少需操作多少次使得序列变成全0序列。分析:序列状态可用一个32位整数表示,状态数目最多为220,所以搜索不会超时,翻转操作可用异或运算来表示。需注意的是,写好后别忘了测试n=1的情况。View Code 1 #include <stdio.h> 2 #include <string.h> 3 #include <math.h> 4 #include <queue> 5 using nam
阅读全文
摘要:典型的搜索题目,将1,2,3,4...8填入上图A,B,C...H中,相邻的字母中的两个数不能相邻。现给定一种初始状态,求能否完成上述要求,若方案唯一,则依次输出完成后A,B,C...H中的数。View Code 1 #include <stdio.h> 2 #include <string.h> 3 #include <vector> 4 #define N 9 5 using namespace std; 6 vector<int> g[N]; 7 int a[N],vis[N],ans[N]; 8 void init() 9 {10 g[1
阅读全文
摘要:水题……View Code 1 #include <stdio.h> 2 #include <string.h> 3 #define N 11 4 char g[N][N]; 5 int t[N][N],n,m,k,cnt; 6 int dx[128],dy[128]; 7 int main() 8 { 9 int i,j;10 dx['E']=0,dx['W']=0;11 dx['S']=1,dx['N']=-1;12 dy['E']=1,dy['W']=-1;13 dy[
阅读全文
摘要:简单bfs题。View Code 1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 #define N 150000 5 using namespace std; 6 queue<int>q; 7 int n,k,t[N]; 8 void bfs() 9 {10 int i;11 memset(t,-1,sizeof(t));12 while(!q.empty()) q.pop();13 t[n]=0;14 q.push(n);15 while(!q.empty())1
阅读全文
摘要:简单搜索题。View Code 1 #include <stdio.h> 2 #define N 100 3 int dx[4]={0,0,1,-1}; 4 int dy[4]={1,-1,0,0}; 5 char g[N][N],n,m,cnt; 6 void dfs(int i,int j) 7 { 8 int ni,nj,d; 9 for(d=0;d<4;d++)10 {11 ni=i+dx[d];12 nj=j+dy[d];13 if(ni<0 || nj<0 || ni>=n || nj>=m || g[ni][nj]!='#'
阅读全文
摘要:简单搜索题。将能走到的地方走一下即可。View Code 1 #include <stdio.h> 2 #define N 20 3 using namespace std; 4 int dx[4]={0,0,1,-1}; 5 int dy[4]={1,-1,0,0}; 6 char g[N][N]; 7 int n,m,cnt; 8 void dfs(int i,int j) 9 {10 int ni,nj,d;11 for(d=0;d<4;d++)12 {13 ni=i+dx[d];14 nj=j+dy[d];15 if(ni<0 || nj<0 ||...
阅读全文
摘要:题目大意:给定一个1-n的排列,规定一种操作,每次只能交换相邻的两个数,求至少进行多少次操作,能将给定的初始态转为目标态,目标态定义为序列中除1外任何一个数都比其左边相邻的那个数大(如果存在),1的左边相邻的数只能是n或者没有。分析:先考虑简单的情况,将初始态转为1,2,3...n。注意到1,2,3...n的逆序数为0,对任何一个序列进行一次上述操作逆序数会增1或减1,如果能保证每次操作都使逆序数减1,那么最少的操作次数便是逆序数,事实正是如此,下面简单证明:当一个序列的逆序数大于0时,则必存在a,b使得a在b的左边且a>b,如果a和b相邻,则交换a,b即可,如果a和b不相邻,则必存在c
阅读全文
摘要:题目链接多维动态规划好题题目大意:给定一个5行9列的中国象棋棋盘(一半),棋盘上红方只剩一个已过河的卒,现黑方让红方连续走k步,求红方最多能吃掉黑方多少棋子。k<=100分析:直接搜索的话肯定会超时(指数级别的复杂度),可以考虑根据卒的位置和其他棋子是否被吃掉来设计状态进行动态规划,关键在于状态的设计,因为卒只能向前冲不能后退,所以后面的行不影响结果,而前面的行中的棋子仍处于初始状态,只有当前行中的棋子的状态需要保存,可以用dp[i][j][k][left][right]表示卒位于i行j列还可以走k步,当前行最左走到left,最右走到right时最多能吃掉多少棋子,状态设计出来了,状态转
阅读全文
摘要:题目链接经典的8数码问题,不要求是最少步数。View Code 1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 #define N 362881 5 #define ABS(x) ((x)>0?(x):(-(x))) 6 using namespace std; 7 const int dx[4]={0,0,1,-1}; 8 const int dy[4]={1,-1,0,0}; 9 char DIR[4]={'r','l','d
阅读全文
摘要:题目链接题目大意:给定一棵树,每个结点有一个值,求一棵含k个结点的子树,使子树的值最大。(树的值为所含结点的值的和)分析:n最大为100,定义状态dp[u][k]为以结点u为根结点且含k个结点的子树的最大值。用左二子右兄弟来存树,不难写出状态转移方程。纠结之处在于使用memset(dp,-1,sizeof(dp))就WA,改成memset(dp,0xff,sizeof(dp))就AC了。其中还有好几次CE莫名其妙,提示信息为"Getting complication error information failed!"AC的代码 1 #include <stdio.h
阅读全文
摘要:题目链接题目大意:给定一个流量网络,网络的拓扑结构是无根树,定义A(k)以结点k为源点,其他叶子结点为汇点的最大流量,求的是A(k)的最大值(k=1,2,3……n)。分析:这题跟树形DP专题Computer那题有点像,那题是距离,这题是流量,本质还是一样。从结点k流出的流量,要么经过儿子结点流出,要么经过父亲结点流出。先DP求每个结点经过儿子结点能流出的最大流量是s[k],在DP求每个结点经过父亲结点能流出的最大流量f[k]。最后结果是MAX(s[k]+f[k]),k=1,2,3...n。s[k]=sum(MIN(s[i],wik)),i是k的儿子结点且不是叶子结点。s[k]=sum(wik)
阅读全文
摘要:题目链接这题跟Balance Act那题差不多,求图的质点。我直接将那题改了一下提交,结果PE了一次,又WA了一次,最后发现是单case,多case的提交为什么WA呢?View Code 1 #include <stdio.h> 2 #include <string.h> 3 #include <vector> 4 #define N 16000 5 #define MAX(a,b) ((a)>(b)?(a):(b)) 6 using namespace std; 7 vector<int> g[N]; 8 int n,p[N],d[N],
阅读全文
摘要:题目大意:给定一棵树,求移除树中哪些结点后,剩下的结点最多的连通支的结点数目不超过原树总结点的一半。分析:先用dfs将无根树转为有根树,在一棵有根树中,去掉某个结点后,剩余的分支为儿子结点所在的分支和父亲结点所在的分支,取结点数目最多的一支即可。View Code 1 #include <stdio.h> 2 #include <string.h> 3 #include <vector> 4 #define N 10000 5 #define MAX(a,b) ((a)>(b)?(a):(b)) 6 using namespace std; 7 vec
阅读全文
摘要:题目链接题目大意:给定一棵树,对树中每一个结点,求其距其他结点的最远距离。分析:最初的想法是对每个结点求一次DFS,那样的话复杂度是O(N2),由于n最大可达10000,所以这个方法肯定会超时。根据树的特殊性可知,每个结点到距其最远的结点,要么通过其儿子结点到达,要么通过其父结点到达,由此想到可用树形动态规划。具体实现时,定义状态df[k],d1[k],d2[k],分别表示结点k通过父结点能到达的最远距离,通过儿子结点能到达的最远距离,通过儿子结点能到达的第二远距离。View Code 1 #include <stdio.h> 2 #include <string.h>
阅读全文
摘要:题目链接题目大意:给定一个连通无向图,每个结点有一个值,现要断开图中某条边,使得原图变成两个连通子图,且要使两个子图的值的差最小。输出最小差,若无法完成,则输出"impossible”分析:要使断开某条边后,原图变成两个连通支,则断开的边一定是桥。对图进行DFS时,得到一颗树,图中有的而树中没有的边叫回边,回边一定不是桥。由此想到可用dfs将图转化为树来做,但树中的边不一定是原图中的桥,问题关键在于桥的判断。此题还需要注意的是可能有重边。View Code 1 #include <stdio.h> 2 #include <math.h> 3 #include
阅读全文
摘要:题目链接题目大意:给定一个有向图(n<100),求最小圈。分析:任何一个圈至少有两个点,在圈中任取两个点i,j,圈的长度可以看成是d[i][j]+d[j][i],所以先用floyd求任意点对的最短距离,然后枚举点对求最小圈长。时间复杂度为O(N3)。View Code 1 #include <stdio.h> 2 #define MIN(a,b) ((a)<(b)?(a):(b)) 3 #define N 100 4 #define INF 0x7fffffff 5 int n,m; 6 int d[N][N]; 7 int main() 8 { 9 int i,j,k
阅读全文
摘要:题目链接题目大意:给定一个无向图,指定2个起点s1和s2和一个终点t,2个人分别从s1和s2出发,目的地是t,求两人的最短路径的最大公共长度(在保证两人均走最短路的前提下使两人一起走的路径最长)。分析:只要两人会合后,就一定会一起走完剩下的全程。所以大体思路是枚举可能的会合点,在判断某个点是否是可能的会合点时,判断这个点是否都是两个人的最短路径上的点即可。求最短路时用到dijkstra。View Code 1 #include <stdio.h> 2 #include <memory.h> 3 #define N 1000 4 #define INF 0x7fffff
阅读全文

浙公网安备 33010602011771号