uva 10511 Councilling(网络流)

Problem C
Councilling
Input: 
Standard Input

Output: Standard Output

 

Each resident of a particular town is a member of zero or more clubs and also a member of exactly one political party. Each club is to nominate one of its members to represent it on the town council so that the number of council members belonging to any given party does not equal or exceed half the membership of the council. The same person may not represent two clubs; that is there must be a 1-1 relationship between clubs and council members. Your job is to select the council members subject to these constraints.

 

Input

In the first line of input there will be an integer T, giving the number of test cases. The next line will be blank. Each of the T test cases consists of up to 1000 lines, each naming a resident, a party, and a list of clubs to which the resident belongs. Names are alphanumeric and separated by a single space. Each resident appears in exactly one input line. Input lines do not exceed 80 characters. Every set of input ends with a blank line.

 

Output

For each test case, follow the following format: Each line should name a council member followed by the club represented by the member. If several answers are possible, any will do. If no council can be formed, print the word "Impossible." in a line. There will be a blank line in between two test cases.

 

Sample Input                               Output for Sample Input

2
 
fred dinosaur jets jetsons
john rhinocerous jets rockets
mary rhinocerous jetsons rockets
ruth platypus rockets
 
fred dinosaur jets jetsons
john rhinocerous jets rockets
mary rhinocerous jetsons rockets
ruth platypus rockets
 
fred jetsons
john jets
ruth rockets
 
fred jetsons
john jets
ruth rockets

 


Problemsetter: G. V. Cormack


题目大意:

T组测试数据,每组测试数据,有很多人,每个人只属于一个党派,而每个人可以属于(0个或多个)俱乐部,现在要求每个俱乐部选1个人出来,而且2个不同俱乐部不能选相同的人,而且最终选出的人,同一党派的要小于选出来的总人数的一半,问你是否可行以及相应方案。


解题思路:

构造了一张网络图来限制流量




其中 源点 与 俱乐部 一对一多,流量为1 ,俱乐部与人一对多,流量为1,人和党派一对一,流量为1,党派和汇点多对一,流量为俱乐部数目的不到一半。

最终查看 网络流俱乐部与人这条边,残余流量为0的这条边就是匹配边,输出即可。


解题代码:


#include <iostream>
#include <cstdio>
#include <queue>
#include <string>
#include <cstring>
#include <vector>
#include <map>
#include <sstream>
using namespace std;

const int maxn=10010;
const int inf=1<<30;
struct edge{
	int u,v,next,f;
	edge(int u0=0,int v0=0,int f0=0,int next0=0){
		u=u0,v=v0,f=f0,next=next0;
	}
}e[maxn*10];
int head[maxn*2],visited[maxn*2],path[maxn*2];
int cnt,from,to,marked;
map <int,string> tos;
int nc,np,nd;

void initial(){
	cnt=0;
	marked=1;
	memset(head,-1,sizeof(head));
	memset(visited,0,sizeof(visited));
	tos.clear();
}

void adde(int u,int v,int f){
	e[cnt].u=u,e[cnt].v=v,e[cnt].f=f,e[cnt].next=head[u],head[u]=cnt++;
	e[cnt].u=v,e[cnt].v=u,e[cnt].f=0,e[cnt].next=head[v],head[v]=cnt++;
}

void input(){
    string st;
    vector <string> v;
    map <string,int> mpc,mpp,mpd;
    map <string,int>::iterator it;
    while(getline(cin,st) && st.length()>0){
        v.push_back(st);
        stringstream ss(st);
        ss>>st;
        mpp[st]=1;
        ss>>st;
        mpd[st]=1;
        while(ss>>st) mpc[st]=1;
    }
    from=0;
    nc=mpc.size();
    np=mpp.size();
    nd=mpd.size();
    to=nc+np+nd+1;
    //to num the string
    it=mpc.begin();
    for(int i=1;i<=nc;i++){
        adde(from,i,1);
        it->second=i;
        tos[it->second]=it->first;
        it++;
    }
    it=mpp.begin();
    for(int i=1;i<=np;i++){
        it->second=nc+i;
        tos[it->second]=it->first;
        it++;
    }
    it=mpd.begin();
    for(int i=1;i<=nd;i++){
        adde(nc+np+i,to,(nc+1)/2-1);
        it->second=nc+np+i;
        tos[it->second]=it->first;
        it++;
    }
    for(int i=0;i<v.size();i++){
        string name,party,club;
        stringstream ss(v[i]);
        ss>>name>>party;
        adde(mpp[name],mpd[party],1);
        while(ss>>club){
            adde(mpc[club],mpp[name],1);
        }
    }
}

bool bfs(){
    int s=from,d;
    queue <int> q;
    q.push(s);
    marked++;
    visited[s]=marked;
    while(!q.empty()){
        s=q.front();
        q.pop();
        for(int i=head[s];i!=-1;i=e[i].next){
            d=e[i].v;
            if(visited[d]!=marked && e[i].f>0){
                visited[d]=marked;
                path[d]=i;
                q.push(d);
                if(d==to) return true;
            }
        }
    }
    return false;
}

int maxf(){
    int maxflow=0;
    while(bfs() ){
        int offflow=inf;
     	for(int i=to;i!=from;i=e[path[i]].u){
     		offflow=min(e[path[i]].f,offflow);
        }
        for(int i=to;i!=from;i=e[path[i]].u){
     		e[path[i]].f-=offflow;
         	e[path[i]^1].f+=offflow;
        }
        maxflow+=offflow;
     }
     return maxflow;
}

void solve(){
    int ans=maxf();
    if(ans>=nc){
        for(int i=0;i<cnt;i++){
            if(e[i].u>=1 && e[i].u<=nc && e[i].v>=nc+1 && e[i].v<=nc+np){
                if(e[i].f<=0){
                    printf("%s %s\n",tos[e[i].v].c_str(),tos[e[i].u].c_str());
                }
            }
        }
    }else printf("Impossible.\n");
}

int main(){
    //freopen("in.txt","r",stdin);
    int t;
    scanf("%d\n",&t);
	for(int i=0;i<t;i++){
		initial();
		input();
		if(i>0) cout<<endl;
		solve();
	}
	return 0;
}




posted @ 2014-04-19 10:14  炒饭君  阅读(250)  评论(0编辑  收藏  举报