HDU_1941
这个题目说白了就是要删掉一些点,而且被删掉的点两两之间不能有边,留下的点两两之间必须有边,也就是构成一个完全图。
乍看起来是没啥思路的,不过大概有两条路子可以走,要么先考虑什么样的点一定会留下来,要么就先考虑什么样的点一定会被删掉。想想之后觉得第二条路子还可行一些,于是就开始想吧。
首先,孤立点是一定可以被删除的(这里以及后面的讨论默认最大度数的点的度数还算比较大),其次好像叶子节点也就是度数为1的点也可以删,再接着好像就不太好讨论了,不过前面这两类点是有共性的,也就是度数比较小,那么是不是先把度数比较小的点删掉就可以了?
不妨考虑一个度数比较小的点A和一个度数比较大的点B,根据两个点集合的从属关系无非有4种情况:①A和B都被删掉了;②A删掉了,B留下;③A留下,B删掉了,不过这种情况是不可以的,因为假设A是完全图中的点,由于B的度数比A大,即便它和完全图中的所有点都有边,那么还是会有多余的度数,所以一定会和删掉的点之间形成边,所以这种情况不可能发生;④A和B都留下了,这也不可能,因为A的度数比B小,不可能和B一起组成完全图。分析完这四种情况就会比较happy了,因为发现无论如何A都会被删掉。于是我们就可以把点按度数排个序,然后从小度数的点开始删。
当然这里还有一个问题需要讨论清,如果A和B的度数相等怎么办?这时删掉A也是无所谓的,因为即便A是完全图中的某个点,那么完全图删掉一个点还会是完全图。那么会不会因为删掉A同时留下B(如果B也能删掉的话肯定就对构成完全图没影响了)而导致不会形成完全图呢?
这时不妨再讨论一下,如果A和B本来是一个完全图中的两个点的话,自然删A和删B的效果是一样的,不会有影响。如果A和B不是一个完全图中的两个点,那么假设A是完全图中的,这时B必然要被删掉,这样B就会有多余的度数和删掉的集合中的点形成边,反过来假设B是完全图中的点,留B删A也是一样的,因此如果A和B不是一个完全图中的两个点,那么本来就不存在合法的方案,于是删A就当玩玩了,反正是无解的,最后判定一下留下的点会不会形成完全图就行了。总而言之,删A不会产生什么不良的后果。
讨论到这里,算法基本就成型了:
基本的思路是将一定会被删掉的点删掉,并保证删掉的点之间没有边,最后看留下的点能否构成完全图。
先把点按度数升序排序,然后从度数较小的开始删,删掉之后更新与之相连的点的度数,并将那些点标记为“必须留下的点”,当扫描到已标记的点的时候就跳过去。最后看留下的点能不能形成完全图。
#include<stdio.h> #include<string.h> #include<algorithm> #define MAXD 50010 #define MAXM 200010 #define INF 0x3f3f3f3f int N, M, first[MAXD], e, next[MAXM], v[MAXM], dgr[MAXD], isin[MAXD], r[MAXD]; bool cmp(const int &x, const int &y) { return dgr[x] < dgr[y]; } void add(int x, int y) { v[e] = y; next[e] = first[x], first[x] = e ++; } void init() { int i, x, y; memset(first, -1, sizeof(first[0]) * (N + 1)), e = 0; memset(dgr, 0, sizeof(dgr[0]) * (N + 1)); for(i = 0; i < M; i ++) { scanf("%d%d", &x, &y); ++ dgr[x], ++ dgr[y]; add(x, y), add(y, x); } } void solve() { int i, j, x, cnt = 0, min = INF; memset(isin, 0, sizeof(isin[0]) * (N + 1)); for(i = 1; i <= N; i ++) r[i] = i; std::sort(r + 1, r + 1 + N, cmp); for(i = 1; i <= N; i ++) if(!isin[x = r[i]]) { for(j = first[x]; j != -1; j = next[j]) -- dgr[v[j]], isin[v[j]] = 1; } for(i = 1; i <= N; i ++) if(isin[x = r[i]]) ++ cnt, min = std::min(min, dgr[x]); printf("%s\n", cnt == min + 1 ? "Y" : "N"); } int main() { while(scanf("%d%d", &N, &M), N) { if(M == 0) { printf("Y\n"); continue; } init(); solve(); } return 0; }