刷题向》关于搜索+tarjan的奇怪组合题 BZOJ1194 (normal+)
关于这道题,其实看懂了的话还是比较好写的,只是题目实在又臭又长,没有让人读下去的勇气。
给出题目翻译:
给你S张图,
每张图有M个点,其中M个点中有N个是特殊单位,会给出。
每个点又有0、1两条边指向其他点。
这样我们每次从0这个点开始,选择向0或者向1走,是不是可以把路径表示成01串的形式捏?
每次我们在模拟路径时,遇到特殊单位就会输出这串01串。
那么图的包含关系定义为:A图输出的所有01串都可以在B中输出(即使是一样的图),这时就称B是A的亲爹;
那么你的任务是找出图中最长的家族关系。
当然不反对大家去看原题,祝大家平安
Description
Input
第一行是一个正整数S,表示宝盒上咒语机的个数,(1≤S≤50)。文件以下分为S块,每一块描述一个咒语机,按照咒语机0,咒语机1„„咒语机S-1的顺序描述。每一块的格式如下。 一块的第一行有两个正整数n,m。分别表示该咒语机中元件的个数、咒语源输出元的个数(1≤m≤n≤50)。 接下来一行有m个数,表示m个咒语源输出元的标号(都在0到n-1之间)。接下来有n行,每一行两个数。第i行(0≤i≤n-1)的两个数表示pi,0和pi,1(当然,都在0到n-1之间)。
Output
第一行有一个正整数t,表示最长升级序列的长度。
Sample Input
4
1 1
0
0 0
2 1
0
1 1
0 0
3 1
0
1 1
2 2
0 0
4 1
0
1 1
2 2
3 3
0 0
1 1
0
0 0
2 1
0
1 1
0 0
3 1
0
1 1
2 2
0 0
4 1
0
1 1
2 2
3 3
0 0
Sample Output
3
那么只要题看懂,恭喜你,这题你就A了一半了。
由于极小的数据,所以判断亲爹的关系可以暴力搜索来解决(谁叫它数据小呢 doge脸)。
然后我们可以把有父子关系的点连边,
然后在图上找最长路就好了,但是由于这道题是允许有环的关系的,所以可以用tarjan缩个点。。。之后再暴搜一遍(doge脸*2)
然后重点就没有啦。。。
由于题目代码会较长,所以可以很好的考察代码能力。
愉快的贴出代码
1 /************************************************************** 2 Problem: 1194 3 User: PencilWang 4 Language: C++ 5 Result: Accepted 6 Time:4692 ms 7 Memory:2964 kb 8 ****************************************************************/ 9 10 #include<stdio.h> 11 #include<string.h> 12 #include<algorithm> 13 using namespace std; 14 int S,s,n,m,a,b; 15 bool Ff[1000],mp[1000][1000],f,F[1000][1000]; 16 int stack[1000],T,low[1000],w[1000],ass,fa[1000],time[1000],mmp[100][100][2],head[3000],point; 17 int pa,pb,headd[1000]; 18 struct shit{ 19 int aim,next,fro; 20 }e[2][3000]; 21 int cn; 22 void tarjan(int x) 23 { 24 time[x]=low[x]=++T; 25 Ff[stack[++ass]=x]=true; 26 for(int i=head[x];i;i=e[0][i].next) 27 { 28 if(!time[e[0][i].aim]) 29 { 30 tarjan(e[0][i].aim); 31 low[x]=min(low[x],low[e[0][i].aim]); 32 } 33 else if(Ff[e[0][i].aim])low[x]=min(low[x],time[e[0][i].aim]); 34 } 35 if(time[x]==low[x]) 36 { 37 Ff[x]=false; 38 w[fa[x]=++cn]=1; 39 while(stack[ass]!=x) 40 { 41 w[fa[stack[ass]]=cn]++; 42 Ff[stack[ass--]]=false; 43 } 44 --ass; 45 } 46 } 47 void dfs(int x,int y) 48 { 49 if(F[x][y]||f)return ; 50 F[x][y]=true; 51 if(!mp[pa][x]&&mp[pb][y]){f=true;return ;} 52 dfs(mmp[pa][x][1],mmp[pb][y][1]); 53 dfs(mmp[pa][x][0],mmp[pb][y][0]); 54 55 } 56 bool check() 57 { 58 memset(F,false,sizeof(F)); 59 f=false; 60 dfs(1,1); 61 return !f; 62 } 63 void fuck(int x,int y) 64 { 65 e[0][++point]=(shit){y,head[x],x};head[x]=point; 66 } 67 int cnt; 68 void rebuild() 69 { 70 for(int i=1;i<=S;i++) 71 { 72 for(int j=head[i];j;j=e[0][j].next) 73 if(fa[i]!=fa[e[0][j].aim]) 74 { 75 e[1][++cnt].aim=fa[e[0][j].aim]; 76 e[1][cnt].next=headd[fa[i]]; 77 e[1][cnt].fro=fa[i]; 78 headd[fa[i]]=cnt; 79 } 80 } 81 } 82 int ans[1000]; 83 int fi(int x) 84 { 85 if(ans[x])return ans[x]; 86 ans[x]=w[x]; 87 for(int i=headd[x];i;i=e[1][i].next) 88 ans[x]=max(ans[x],fi(e[1][i].aim)+w[x]); 89 return ans[x]; 90 } 91 int find_ans() 92 { 93 int sb_1=0; 94 for(int i=1;i<=cn;i++)sb_1=max(sb_1,fi(i)); 95 return sb_1; 96 } 97 int main() 98 { 99 scanf("%d",&S); 100 for(s=1;s<=S;s++) 101 { 102 fa[s]=s; 103 scanf("%d%d",&n,&m); 104 for(int i=1;i<=m;i++) 105 { 106 scanf("%d",&a); 107 mp[s][a+1]=true; 108 } 109 for(int i=1;i<=n;i++) 110 { 111 scanf("%d%d",&a,&b); 112 mmp[s][i][0]=a+1;mmp[s][i][1]=b+1; 113 } 114 } 115 for(int i=1;i<=S;i++) 116 for(int j=1;j<=S;j++) 117 { 118 if(j==i)continue; 119 pa=i; 120 pb=j; 121 if(check()){fuck(i,j);} 122 } 123 for(int i=1;i<=S;i++) 124 if(!time[i])tarjan(i); 125 rebuild(); 126 printf("%d",find_ans()); 127 return 0; 128 }