POJ 1703 Find them, Catch them
2014-02-25 15:25
495 查看
题目大意:
Tadu城的警察想和混乱说拜拜,准备行动起来铲除城中的两大黑帮——龙帮和蛇帮,但首先他们得弄清楚罪犯到底属于哪个帮才能准确定罪,现在的问题是给你两个罪犯,你能否判断他们两是否属于同一帮。
现有多个测例(测例数题中会给出),假设每个测例中会告诉你罪犯总共有N个(N ≤ 100,000,其编号为1-N),每个罪犯只属于两个帮派中的一个,接下来会有M条信息给你处理:
D a b
表示a和b属于不同帮派;
A a b
让你给出判断,判断a和b是否属于同一帮派(也有可能无法判断,依据前面给出的信息来判断);
题目链接
思路一:将D信息中的两个罪犯合并在同一集合中,表示(a, b)对被考察过了,然后利用各自和并查集根的关系判断他们是否在同一帮派中。
注释代码:
思路二:敌人的敌人就是朋友
注释代码:
单词解释:
chaos:n, 混乱
launch:vt, 发射
launch action:采取行动,启动任务
root up:vt, 根除,肃清
gangs:n, 帮派,黑帮
criminal:n, 罪犯
clan:n, 集团,部落
incomplete:adj, 不完全的,不完备的
gangster:n, 歹徒
Tadu城的警察想和混乱说拜拜,准备行动起来铲除城中的两大黑帮——龙帮和蛇帮,但首先他们得弄清楚罪犯到底属于哪个帮才能准确定罪,现在的问题是给你两个罪犯,你能否判断他们两是否属于同一帮。
现有多个测例(测例数题中会给出),假设每个测例中会告诉你罪犯总共有N个(N ≤ 100,000,其编号为1-N),每个罪犯只属于两个帮派中的一个,接下来会有M条信息给你处理:
D a b
表示a和b属于不同帮派;
A a b
让你给出判断,判断a和b是否属于同一帮派(也有可能无法判断,依据前面给出的信息来判断);
题目链接
思路一:将D信息中的两个罪犯合并在同一集合中,表示(a, b)对被考察过了,然后利用各自和并查集根的关系判断他们是否在同一帮派中。
注释代码:
/* * Problem ID : POJ 1703 Find them, Catch them * Author : Lirx.t.Una * Language : C++ * Run Time : 297 ms * Run Memory : 616 KB */ #include <string.h> #include <stdio.h> //maximum number of criminals,罪犯的最大数量 //100,000 + 1 #define MAXN 100001 #define TRUE 1 #define FALSE 0 int set[MAXN];//考查集合,将所有考查过的罪犯纳入一个集合 char r[MAXN];//relationship,每个罪犯和根结点的关系 //若和根结点在同一帮派则为TRUE,否则为FALSE int find(int x) { if ( x == set[x] ) return x; int f; f = set[x];//保存x的老根 set[x] = find(f);//对x路径压缩 //由于x被路径压缩了,所以其根结点改变了 //接在新的根结点上后需要更新它和新根的关系 //新关系可以由它跟老根的关系和老根和新根的关系推出 //(因为这是递归进行的,因此老根在上面递归结束后必然接在了现在的新根上, //并且它跟新根的关系已经递归地更新过了,所以在这一层上可以放心利用老根和 //新根的关系) //若它俩关系相同那么必然x和新根在同一帮派,否则就处于不同帮派 r[x] = !( r[x] ^ r[f] ); return set[x]; } int main() { int t;//测例数 int n;//罪犯总数 int m;//信息总数 int i;//计数变量 char cmd;//信息中的命令部分 int a, b;//信息中的两个罪犯的编号 int sa, sb;//set of a and b,a和b的根结点(即所属的集合) scanf("%d", &t); while ( t-- ) { scanf("%d%d", &n, &m); //由于初始化时每个罪犯的信息未知,所以每个人都归到以自己 //为编号的集合中,因此自己就是根结点,自己和根结点必然都 //同属于一个帮派,所以都初始化为TRUE memset(r + 1, TRUE, n * sizeof(char)); //并查集初始化 for ( i = 1; i <= n; i++ ) set[i] = i; while ( m-- ) { scanf("\n%c%d%d", &cmd, &a, &b); sa = find(a); sb = find(b); switch (cmd) { case 'A' : if ( sa != sb ) {//代表a、b对还没有考察过 puts("Not sure yet."); break; } if ( r[a] == r[b] ) {//现a、b同属一个集合了 //若a、b和各自的根(两根相同)的关系 //相同,则他俩必定在同一帮派中 puts("In the same gang."); break; } puts("In different gangs.");//否则必定不在一个帮派中 break; default ://若为D if ( sa != sb ) {//a、b不在一个集合中 //这就说明a、b对还没有被考察过 //以下对a、b两个所属的集合进行合并 set[sa] = sb;//sa的根发生变化(本来sa的根就是自己) //sa换了新根后需要对其和新根的关系进行更新 //该关系可以从a和b的关系,以及a、b各自的老根的关系推出 //由于a和b必定不在一个帮派中 //所以如果r[a]、r[b]相同,则r[sa]必定为FALSE,否则为TRUE r[sa] = !!( r[a] ^ r[b] ); break; } } } } return 0; }无注释代码:
#include <string.h> #include <stdio.h> #define MAXN 100001 #define TRUE 1 #define FALSE 0 int set[MAXN]; char r[MAXN]; int find(int x) { if ( x == set[x] ) return x; int f; f = set[x]; set[x] = find(f); r[x] = !( r[x] ^ r[f] ); return set[x]; } int main() { int t; int n; int m; int i; char cmd; int a; int b; int sa; int sb; scanf("%d", &t); while ( t-- ) { scanf("%d%d", &n, &m); memset(r + 1, TRUE, n * sizeof(char)); for ( i = 1; i <= n; i++ ) set[i] = i; while ( m-- ) { scanf("\n%c%d%d", &cmd, &a, &b); sa = find(a); sb = find(b); switch (cmd) { case 'A' : if ( sa != sb ) { puts("Not sure yet."); break; } if ( r[a] == r[b] ) { puts("In the same gang."); break; } puts("In different gangs."); break; default : if ( sa != sb ) { set[sa] = sb; r[sa] = !!( r[a] ^ r[b] ); break; } } } } return 0; }
思路二:敌人的敌人就是朋友
注释代码:
/* * Problem ID : POJ 1703 Find them, Catch them * Author : Lirx.t.Una * Language : C++ * Run Time : 297 ms * Run Memory : 912 KB */ #include <stdio.h> //前一半表示罪犯所在帮派,后一半表示罪犯的对手所在的帮派 #define MAXN 200001 int set[MAXN]; int find(int x) { if ( x == set[x] ) return x; return set[x] = find( set[x] ); } void union_set( int sx, int y ) { int sy; sy = find(y); if ( sx == sy ) return ; set[sx] = sy; } int main() { int t; int n; int m; int i; int a, b; int sa, sb; char cmd; scanf("%d", &t); while ( t-- ) { scanf("%d%d", &n, &m); for ( i = 1; i <= n + n; i++ ) set[i] = i; while ( m-- ) { scanf("\n%c%d%d", &cmd, &a, &b); sa = find(a); sb = find(b); switch (cmd) { case 'A' : if ( sa == sb ) { puts("In the same gang."); break; } if ( sa == find( b + n ) ) {//若a和b的对手在同一帮派 //则表示a、b肯定在不同帮派 puts("In different gangs."); break; } puts("Not sure yet."); break; default : union_set( sa, b + n );//将a和b的对手合并到一个帮派 union_set( sb, a + n );//同时也需要将b和a的对手合并到一个帮派 break; } } } return 0; }无注释代码:
#include <stdio.h> #define MAXN 200001 int set[MAXN]; int find(int x) { if ( x == set[x] ) return x; return set[x] = find( set[x] ); } void union_set( int sx, int y ) { int sy; sy = find(y); if ( sx == sy ) return ; set[sx] = sy; } int main() { int t; int n; int m; int i; int a, b; int sa, sb; char cmd; scanf("%d", &t); while ( t-- ) { scanf("%d%d", &n, &m); for ( i = 1; i <= n + n; i++ ) set[i] = i; while ( m-- ) { scanf("\n%c%d%d", &cmd, &a, &b); sa = find(a); sb = find(b); switch (cmd) { case 'A' : if ( sa == sb ) { puts("In the same gang."); break; } if ( sa == find( b + n ) ) { puts("In different gangs."); break; } puts("Not sure yet."); break; default : union_set( sa, b + n ); union_set( sb, a + n ); break; } } } return 0; }
单词解释:
chaos:n, 混乱
launch:vt, 发射
launch action:采取行动,启动任务
root up:vt, 根除,肃清
gangs:n, 帮派,黑帮
criminal:n, 罪犯
clan:n, 集团,部落
incomplete:adj, 不完全的,不完备的
gangster:n, 歹徒
相关文章推荐
- Java数组及其常用类
- 7.11.1: 基于XML Schema的简化配置方式---使用p名称空间配置属性
- 应用netlink的内核模块和应用程序Makefile编写
- android ndk调试工具
- Opencv 完美配置攻略 2014 (Win8.1 + Opencv 2.4.8 + VS 2013)
- 消息机制--AsyncTask(2)
- SVN
- beanMap
- Openmeeting 网页打开缓慢,视频卡的一个解决方法
- 同源策略
- 职场中那些优秀的品格
- vim格式化代码
- 使用Extended Events收集错误信息
- el,jstl使用
- 关于Android SDK无法更新的解决办法
- 新兵报到
- 书籍
- JVM—工作原理
- gvim实用配置
- step5-LINQ