Papa的坦克(原BZOJ 1603 打谷机)
题目描述
时间限制 1s 空间限制 128MB Papa有一辆很厉害的坦克,它需要齿轮来带动。发动机驱动轮1总是顺时针旋转的,用来带动转轮2,转轮2来带动转轮3,等等。
一共有n(2<=n<=1000)个齿轮(和n-1条链条)。齿轮有两种连接方式,第一种方式使得两个轮子旋转的方向相同,第二种则相反。 给出一串带子的信息: Si—驱动轮 Di—被动轮 *Ci—连接的类型(0=直接连接,1=交叉连接) 不幸的是,列出的信息是随机的。 作为样例, n=4,转轮1是驱动轮,可以得知最后转轮4是逆时针旋转。
输入格式
第一行:一个数n 第二行到第n行:每一行有三个被空格隔开的数:Si,Di,Ci
输出格式
第一行:一个单独的数,表示第n个转轮的方向,0表示顺时针,1表示逆时针
样例输入
4
2 3 0
3 4 1
1 2 0
样例输出
1
嗯...这是我们学校测试的第一题,虽然不难,但还是考验图论的基本功的,有意想做了测评的到该站 http://www.nyzoj.com:5283/problem/10037
dfs解法:
因为建边时驱动轮在前,被动轮在后,所以只用建单向边就可以了
然后dfs从1开始遍历到n,我们用一个f[]数组来存状态,因为0表示顺时针,所以起始的f[1]只要定义成全局变量就不用初始化了
在dfs过程中要用到“^” 运算符,意思是“异或” ,如果a=b then a^b=0 else return |a-b|
就很好的运用到了本题,如果下一个轮的连接方式与上一个轮的转向相同则为顺,即是 0 ,不同则为逆,则是 1
代码如下:
#include<stdio.h> struct Edge{ int to,next,val; }edge[1001]; int n,cnt,first[1001],f[1001]; void add(int from,int to,int val) { edge[++cnt].to=to; edge[cnt].val=val; edge[cnt].next=first[from]; first[from]=cnt; } void dfs(int x,int from) { for(int i=first[x];i;i=edge[i].next) { f[edge[i].to]=f[x]^edge[i].val; dfs(edge[i].to,x); } } int main() { scanf("%d",&n); int from,to,val; while(scanf("%d%d%d",&from,&to,&val)!=EOF){ add(from,to,val); } dfs(1,0); printf("%d",f[n]); return 0; }
拆点并查集解法:
#include<cstdio> #include<cstring> int ufs[5000]; int Find(int x) { return ufs[x] ==x?x:ufs[x]= Find(ufs[x]); } int main() { int n, i, t1, t2, x, y, t; scanf("%d", &n); { memset(ufs, 0, sizeof(ufs)); for(i=1; i<=n*2+1 ;i++) ufs[i]=i; for(i=1;i<=n-1;i++) { scanf("%d%d%d", &x, &y, &t); if(t==0) { t1 = Find(x); t2 = Find(y); ufs[t1] = t2; t1 = Find(x+n); t2 = Find(y+n); ufs[t1] = t2; } else { t1 = Find(x); t2 = Find(y+n); ufs[t1] = t2; t1 = Find(x+n); t2 = Find(y); ufs[t1] = t2; } } if(Find(1)==Find(n)) printf("0\n"); else printf("1\n"); } return 0; }
从0到1很难,但从1到100很容易