poj-1703
来源:互联网 发布:淘宝端口急速退款 编辑:程序博客网 时间:2024/05/16 18:17
//940K 469MS C++// cin TLE...#include <cstdio>#include <cstring>#include <cassert>#include <iostream>using namespace std;const int MAX = 100100;int UF_set[MAX];int hate[MAX];int caseNum;int criminalNum;int messageNum;void UF_getSetId(int curId) { if (UF_set[curId] == 0) { return; } int topId = UF_set[curId]; while(UF_set[topId] != topId) { topId = UF_set[topId]; } UF_set[curId] = topId;}void UF_fill(int A, int B) { UF_getSetId(A); UF_getSetId(B); int AsetId = UF_set[A]; int BsetId = UF_set[B]; if (!AsetId && !BsetId) { // A and B first filled, belong to different set and hate each other. UF_set[A] = A; UF_set[B] = B; hate[A] = B; hate[B] = A; } else if (AsetId && !BsetId) { // A has been filled, B not, B is added in the set which hated by A'set // also update hate[]; int ASetHate = hate[AsetId]; UF_set[B] = ASetHate; hate[A] = hate[AsetId]; hate[B] = AsetId; } else if (!AsetId && BsetId) { // B has been filled, A not, A is added in the set which hated by B'set // also update hate[]; int BSetHate = hate[BsetId]; UF_set[A] = BSetHate; hate[A] = BsetId; hate[B] = hate[BsetId]; } else if (AsetId && BsetId) { // A and B all filled before, should not in same set(becasue A and B hate each other) // assert(AsetId != BsetId); // get A's set's hate set, add B's set in this set. // and add B's set's hate set in A set. int ASetHate = hate[AsetId]; if (ASetHate != BsetId) { int BSetHate = hate[BsetId]; hate[BsetId] = AsetId; UF_set[BsetId] = ASetHate; hate[B] = AsetId; UF_set[BSetHate] = AsetId; hate[BSetHate] = ASetHate; } }}void ifSameGang(int A, int B) { UF_getSetId(A); UF_getSetId(B); int AsetId = UF_set[A]; int BsetId = UF_set[B]; // if A or B never filled if (!AsetId || !BsetId) { printf("Not sure yet.\n"); } else if (AsetId == BsetId) { printf("In the same gang.\n"); } else { if (hate[AsetId] == BsetId) { printf("In different gangs.\n"); } else { printf("Not sure yet.\n"); } }}char message[100];int main() { scanf("%d", &caseNum); for (int i = 1; i <= caseNum; i++) { memset(UF_set, 0, sizeof(UF_set)); memset(hate, 0, sizeof(hate)); scanf("%d %d", &criminalNum, &messageNum); for (int i = 1; i <= messageNum; i++) { int A; int B; // cin>>message>>A>>B; scanf("%s", message); if (message[0] == 'D') { scanf("%d %d", &A, &B); // printf("%c %d %d\n", message, A, B); UF_fill(A, B); } else if (message[0] == 'A') { scanf("%d %d", &A, &B); // printf("%c %d %d\n", message, A, B); ifSameGang(A, B); } } }}
一道并查集的中级应用题, 这道题的最大难点是,对于给定的一组输入, 除了知道两者是对立的以外,并不知道谁到底属于哪一方,
A与B对立,但是A和B的归属会有两种情况:
A属于dragon, B属于snake
A属于snake, B属于dragon,
用并查集显然无法表示这种模棱两可的情况,因此这种情况下,就不急着将A和B直接归类到dragon/snake. 而是令其现自立门派,分别属于自己的gang,即并查集中
A和B分别是两个set,且setId分别是A和B,
具体的操作例子:
当前加入了
A <->B,
C<->D,
那么现在set的情况是: 一共有4个set,set的根分别就是 A,B,C,D,接下来加入新的对立关系,共有这些case:
case1: E<->F, E 和 F和之前加入的A B C D都没有关系,那么继续E和F建立自己的帮派, 一共有6个set了。
case2: A <->E, 因为已经知道A和B是对立的,那么E和B必然是一个帮派的,那么就将E加入到B的帮派中。
case3: B<->C, 因为知道 B和A对立,那么C必然和A一个帮派,那么将C加入到A帮派中, 而D和C对立,也就是和AC帮派对立,那么D一定和B一个帮派,将D加入到B帮派中。
就这样操作,
最后会会得到一些集合(因为题目并不保证最后一定会将子帮派彻底合并成dragon和snake, 比如,最后可能就是 A <->B. C<->D这个四个帮派),并且还要维护一个对立列表hate来记录对于某个帮派,其对立帮派是哪个,这样才能正确的判断,某两人是是对立还是不能确定。
在query对立关系的时候,如果A和B都属于一个帮派,那么好办,
如果不属于一个帮派,就需要检查所属于的两个帮派是否对立了.
- poj 2492 && poj 1703
- poj 1703
- POJ 1703
- poj 1703
- POJ 1703
- poj 1703
- poj 1703
- POJ 1703
- POJ 1703
- poj-1703
- poj-1703
- poj 1703
- POJ 1703
- poj 1703
- POJ 1703
- poj 1703
- POJ 1703
- poj 1703
- 使用CMD命令打WAR包
- 浅谈JavaBean,Entity Bean,Enterprise Bean等Bean以及POJO的含义
- 获取线程id的另一种方法
- Android复习练习六(安卓文件读写权限)
- 使用cobbler安装centos
- poj-1703
- XDOJ1181 - 烤面包
- python操作MySQL数据库
- py2exe使用方法——python程序打包
- Looking for files that have been modified recently
- git 代理设置
- 过电压保护器的工作原理图
- 编译安装openssl
- Android中常用的位图操作(View与Bitmap转化、圆角、灰化、提取Alpha、旋转、倒影、剪切……)