POJ 1112 Team Them Up! 二分图判定+01背包
题目链接:
http://poj.org/problem?id=1112
Team Them Up!
Memory Limit: 10000K
样例输出
3 1 3 5
2 2 4
题意
给你若干个人,要把他们分成两组,其中同一组内要保证任意两个人互相认识(题目给的边都是单向边),求一个使得两组人数最接近的方案,要求输出一个可行分组方案。
题解
首先,把关系图建处理(对于(u,v)如果不存在(v,u)相当于这条边不存在),处理出补图,然后题目就转换成了一个二分图问题了,跑下黑白染色,判断是否有可行解,如果有,则用dp跑下,求出最优解就ok啦。dp[i][j]表示已经处理了i个联通分量(跑黑白染色会处理出若干个联通分量),其中一组能凑出j个人的方案。
代码
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<sstream>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
const int maxn=111;
int n;
bool gra[maxn][maxn];
bool dp[maxn][maxn];
VI lis[maxn][3];
int color[maxn],tot;
//黑白染色
bool dfs(int u) {
    for(int v=1; v<=n; v++) {
        if(!gra[u][v]) continue;
        if(!color[v]) {
            color[v]=3-color[u];
            lis[tot][color[v]].pb(v);
            bool su=dfs(v);
            if(!su) return false;
        } else {
            if(color[v]==color[u]) return false;
        }
    }
    return true;
}
VI ans[3];
bool used[maxn];
//处理出最优方案
void print(int i,int j) {
    if(i==0) {
        return;
    }
    int a=lis[i][1].sz(),b=lis[i][2].sz();
    if(j>=a&&dp[i-1][j-a]) {
        print(i-1,j-a);
        rep(ii,0,lis[i][1].sz()) {
            ans[1].pb(lis[i][1][ii]);
        }
    } else if(j>=b&&dp[i-1][j-b]) {
        print(i-1,j-b);
        rep(ii,0,lis[i][2].sz()) {
            ans[1].pb(lis[i][2][ii]);
        }
    }
}
int main() {
    while(scf("%d",&n)==1&&n) {
        clr(gra,0);
        for(int i=1; i<=n; i++) {
            int v;
            while(scf("%d",&v)==1&&v) {
                gra[i][v]=1;
            }
        }
        for(int i=1; i<=n; i++) {
            for(int j=1; j<i; j++) {
                gra[i][j]=gra[j][i]=!(gra[i][j]&&gra[j][i]);
            }
        }
        //黑白染色
        clr(color,0);
        rep(i,0,maxn) lis[i][1].clear(),lis[i][2].clear();
        tot=0;
        bool su=1;
        for(int i=1; i<=n; i++) {
            if(!color[i]) {
                ++tot;
                color[i]=1;
                lis[tot][1].pb(i);
                su=dfs(i);
            }
            if(!su) break;
        }
        if(!su) {
            prf("No solution\n");
            continue;
        }
        //01背包,不是选和不选,而是选1还是选2.
        clr(dp,0);
        dp[0][0]=1;
        for(int i=1; i<=tot; i++) {
            int a=lis[i][1].sz(),b=lis[i][2].sz();
            for(int j=0; j<=100; j++) {
                if(j>=a&&j>=b) {
                    dp[i][j]=dp[i-1][j-a]|dp[i-1][j-b];
                } else if(j>=a) {
                    dp[i][j]=dp[i-1][j-a];
                } else if(j>=b) {
                    dp[i][j]=dp[i-1][j-b];
                }
            }
        }
        //输出最优方案
        int Mi=INF,pos=-1;
        for(int i=1; i<=100; i++) {
            if(dp[tot][i]) {
                if(Mi>abs(i-(n-i))) {
                    Mi=abs(i-(n-i));
                    pos=i;
                }
            }
        }
        ans[1].clear(),ans[2].clear();
        clr(used,0);
        print(tot,pos);
        rep(i,0,ans[1].sz()) used[ans[1][i]]=1;
        for(int i=1; i<=n; i++) {
            if(!used[i]) ans[2].pb(i);
        }
        sort(all(ans[1]));
        sort(all(ans[2]));
        for(int i=1; i<=2; i++) {
            prf("%d ",ans[i].sz());
            rep(j,0,ans[i].sz()) prf("%d%c",ans[i][j],j==ans[i].sz()-1?'\n':' ');
        }
    }
    return 0;
}
//end-----------------------------------------------------------------------
/*
3
2 0
1 3 0
2 0
*/
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号