暑假集训单切赛第二场 UVA 10982 Troublemakers

题意:将点放在两个集合,同一个集合的边保留,不同集合的边删去,使得边至少减少一半。
   输出任何一种方案即可。如果不能,输出Impossible
 
思路:设如果两个人为一对捣蛋鬼,则two[i][j]=two[j][i]=1,即用边表示关系
   刚开始设集合为A、B,为空集。然后每次取一个点,往集合里加,加入到哪个集合使得增加的边最少就加入到那个集合中。

 

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

int two[110][110];//two[i][j]=1表示i和j是一对捣蛋鬼
int n,m;
int vis[110];//vis[i]=1表示i放入集合A中,=2表示i放在集合B中
int group[3];//group[1]统计A中的点的个数,group[2]统计B中的点的个数。

int main() {
    int t,a,b;
    scanf("%d",&t);
    for(int q=1; q<=t; q++) {
        memset(vis,0,sizeof(vis));
        memset(group,0,sizeof(group));
        memset(two,0,sizeof(two));
        scanf("%d%d",&n,&m);
        for(int i=1; i<=m; i++) {
            scanf("%d%d",&a,&b);
            two[a][b]=two[b][a]=1;
        }
        int num=0;
        //每次取一个点插入到集合A或B中
        for(int i=1; i<=n; i++) {
            int tmp1=0,tmp2=0;   //tmp1表示将点i放入到集合A中将产生多少条边,tmp2表示将点i放入到集合B中将产生多少条边
            for(int j=1; j<=n; j++) {
                if(vis[j]==1 && two[i][j]) {
                    tmp1++;
                }
                if(vis[j]==2 && two[i][j]) {
                    tmp2++;
                }
            }
            //放入哪个集合增加的边少,就将点i放入到哪个集合中
            if(tmp1>tmp2) {
                vis[i]=2;
                group[2]++;
                num+=tmp2;
            } else {
                vis[i]=1;
                group[1]++;
                num+=tmp1;
            }
        }
        if(num<=m/2) {
            printf("Case #%d: %d\n",q,group[1]);
            for(int i=1; i<=n; i++) {
                if(vis[i]==1)
                    printf("%d ",i);
            }
            printf("\n");
        } else {
            printf("Case #%d: Impossible.\n",q);
            printf("\n");
        }
    }
    return 0;
}

 

posted @ 2013-08-28 18:51  辰曦~文若  阅读(440)  评论(0编辑  收藏  举报