【9505】部落卫队

Time Limit: 1000ms second
Memory Limit: 32m 问题描述:
原始部落byteland中的居民们为了争夺有限的资源,经常发生冲突。几乎每个居民都有他的仇敌。部落酋长为了组织一支保卫部落的队伍,希望从部落的居民中选出最多的居民入 伍,并保证队伍中任何2个人都不是仇敌。
编程任务:
给定byteland 部落中居民间的仇敌关系,编程计算组成部落卫队的最佳方案。

Input

第1行有2个正整数n和m,表示byteland部落中有n个居民,居民间有m个仇敌关系。居民编号为1,2,…,n。接下来的m行中,每行有2个正整数u和v,表示居民u与居民v是仇敌。 (居民编号为1,2,...,n)

Output

程序运行结束时,将计算出的部落卫队的最佳组建方案输出到文件output.txt 中。文件 的第1行是部落卫队的顶人数;文件的第2行是卫队组成xi,1≤i≤n,xi=0表示居民i不在卫队中,xi=1表示居民在卫队中。(第二行数据后都加一空格,最后以回车结束)

Sample Input

7 10
1 2
1 4
2 4
2 3
2 5
2 6
3 5
3 6
4 5
5 6


Sample Output

3
1 0 1 0 0 0 1 

【题解】

用一个二维数组来表示某个人的所有仇敌关系,a[i][0]表示i号人他的仇敌数量,a[i][1..a[i][0]]则表示这a[i][0]个人具体是谁。

当我们想要把第i个人放入这个卫队中时,我们先看下现在的卫队中是否有人以他为仇敌。如果没有就放进去。然后我们需要更新这支队伍的仇敌列表,即不能进入这支新队伍的人。在找的时候一边更新最优解就好。

这题仍然是组合问题,因为1 3 7 和 3 1 7是一样的。所以扫描到x的时候从x+1开始扫描就好。

【代码】

在vijos上也有这题P1593,那里有10个数据,平台上只剩2个数据了。

#include <cstdio>

int n,m,num = 0,max_n = 0;
int a[1001][1001]; //3MB
int bo[1001],ans[1001],tt[1001];

void input_data()
{
    scanf("%d %d",&n,&m);
    for (int i = 1; i <= n;i++)
        for (int j = 1; j<= m;j++) //一开始的初始化 所有人都没有仇敌
            a[i][j] = 0;
    for (int i = 1;i <= m;i++) //增加m个仇敌关系
        {
            int x,y;
            scanf("%d %d",&x,&y);
            a[x][0]++;a[x][a[x][0]] = y; //两个人都各增加一个仇敌 并记录下来
            a[y][0]++;a[y][a[y][0]] = x;
        }
    for (int i = 1;i <= n;i++) //一开始所有人都可以进入这个队伍
        bo[i] = 0;
}

void sear_ch(int x)
{
    bo[x] = 1; //这个人入队后直接变成1 之前肯定是0的
    for (int i = 1;i <= a[x][0];i++) //这个人地仇敌,每个仇敌的bo都递增,注意不要直接变成0.比如里面有两个人
        //仇敌都有3。我们这层搜索完后,应该递减,而不是直接变成false,这样bo[3]==1,我们下次就不会把3给加进去了。
        bo[a[x][i]]++;
    ans[++num] = x; //记录答案
    if (num >max_n) //如果大于最大值 就更新解
        {
            max_n = num;
            for (int i = 1;i <= max_n;i++)
                tt[i] = ans[i];
        }
    for (int i = x+1;i <= n;i++) //从x+1开始 如果可以加入就加入
        if (bo[i] == 0)
            sear_ch(i);
    for (int i = 1;i <=a[x][0];i++)//注意是递减不是直接变成0
        bo[a[x][i]]--;
    bo[x] = 0; //本身是可以直接变成0的,因为bo[x]一开始直接变成1,后来仇敌增加,此外没有涉及到,有也已经递减了。
    num--;
}

void get_ans()
{
    for (int i = 1;i <= n;i++)
        sear_ch(i);
    for (int i = 1;i <= n;i++) //根据记录的答案改变各个编号的人的值。最后输出就好
        bo[i] = 0;
    for (int i = 1;i <= max_n;i++)
        bo[tt[i]] = 1;
}

void output_ans()
{
    printf("%d
",max_n);
    for (int i = 1;i <= n;i++)
        printf("%d ",bo[i]);
}

int main()
{
    //freopen("F:\rush.txt","r",stdin);
    input_data();
    get_ans();
    output_ans();
    return 0;
}


 

 

原文地址:https://www.cnblogs.com/AWCXV/p/7632439.html