UOJ #596. 罪犯分组


【题目描述】:

B 城有一座监狱,一共关押着N 名罪犯,编号分别为1-N。

他们的关系十分不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。

在详细考察了N 名罪犯间的矛盾关系后,警察局长发现罪犯之间的矛盾关系可以用一个N 个点M 条边的无向图来表示:如果x 到y 有一条边,表示罪犯x 和罪犯y 有矛盾。

现在警察局长要把这些罪犯分成一些小组,每名罪犯属于且仅属于一个小组。

为了开展活动顺利,要求每个小组内最多有K 对罪犯有矛盾,同时为了管理方便,警察局长希望最小化分成的小组数量。

那么,应如何分配罪犯,才能使分成的小组数量最少?这个最小值是多少?
【输入描述】:

第一行3个整数,N,M,K;

以下M行,每行两个数字x,y。表示x和y之间有矛盾。
【输出描述】:

输出一行一个值,表示最少的分组数量。
【样例输入】:

3 3 1
1 2
2 3
1 3

【样例输出】:

2

【时间限制、数据范围及描述】:

时间:1s 空间:256M

对于每个测试点,N分别为:2,4,6,8,10,12,14,15,16,16;

0≤M,K≤N(N-1)/2;

保证是一个无自环、无重边的无向图。

本题设f(S)为集合S需要的最小分组数。
则f(S)=min{ f(S−S0)+1 | S0⫋S,S0集合可分成1组 }
要枚举全集的所有子集的所有子集,时间复杂度是O(3^n)

Code:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<deque>
using namespace std;
const int N=25,INF=0x3f3f3f3f;
int n,m,k,f[1<<N],map[N][N];
bool lim[1<<N];
int main(){
	int x,y;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		map[x][y]=map[y][x]=1;
	}
    for(int s=1;s<(1<<n);s++){
        int cnt=0;
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
				if(map[i][j]&&(s&(1<<(i-1)))&&(s&(1<<(j-1)))){
					++cnt;
				}
			}
		}
        if(cnt>k){
			lim[s]=false;
		}
		else{
			lim[s]=true;
		}
    }
    for(int s=1;s<(1<<n);s++){
        if(lim[s]){
			f[s]=1;
		}
		else{
			f[s]=INF;
		}
        for(int s1=(s-1)&s;s1>0;s1=(s1-1)&s){
            if(lim[s1]){
                f[s]=min(f[s],f[s-s1]+1);
            }
        }
    }
    printf("%d\n",f[(1<<n)-1]);
    return 0;
}
posted @ 2019-09-26 23:43  prestige  阅读(469)  评论(0编辑  收藏  举报