网络流|二分图+uva11045


  My T-shirt suits me 

Our friend Victor participates as an instructor in an environmental volunteer program. His boss asked Victor to distribute N T-shirts to M volunteers, one T-shirt each volunteer, where N is multiple of six, and N$ \ge$M. There are the same number of T-shirts of each one of the six available sizes: XXL, XL, L, M , S, and XS. Victor has a little problem because only two sizes of the T-shirts suit each volunteer.


You must write a program to decide if Victor can distribute T-shirts in such a way that all volunteers get a T-shirt that suit them. If N $ \neq$ M, there can be some remaining T-shirts.

Input 

The first line of the input contains the number of test cases. For each test case, there is a line with two numbers N and MN is multiple of 6, 1$ \le$N$ \le$36, and indicates the number of T-shirts. Number M1$ \le$M$ \le$30, indicates the number of volunteers, with N$ \ge$M. Subsequently, M lines are listed where each line contains, separated by one space, the two sizes that suit each volunteer (XXL, XL, L, M , S, or XS).

Output 

For each test case you are to print a line containing YES if there is, at least, one distribution where T-shirts suit all volunteers, or NO, in other case.

Sample Input 

 
3
18 6
L XL
XL L
XXL XL
S XS
M S
M L
6 4
S XL
L S
L XL
L XL
6 1
L M

Sample Output 

 
YES
NO
YES

思路:源点与每个人之间建一条容量为1的边,人与型号之间建立容量为1的边,型号与汇点建立容量为n/6的边,求最大流。
下面是代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
const int maxn=50;
const int INF=1000000000;
struct node
{
    int v,next,f;
}edge[maxn*10];
int n,m,num,nn;
int head[maxn],pre[maxn],gap[maxn],dis[maxn],vis[maxn],cur[maxn];
int change(string x)
{
    if(x=="XXL")return m+1;
    else if(x=="XL") return m+2;
    else if(x=="L") return m+3;
    else if(x=="M") return m+4;
    else if(x=="S") return m+5;
    else if(x=="XS") return m+6;
}
void init()
{
    num=0;
    memset(head,-1,sizeof(head));
}
void add_edge(int x,int y,int f)
{
    edge[num].v=y;
    edge[num].next=head[x];
    edge[num].f=f;
    head[x]=num++;
    edge[num].v=x;
    edge[num].next=head[y];
    edge[num].f=0;
    head[y]=num++;
}
int sap(int s,int t)
{
    for(int i=0;i<=nn;i++)
    {
        dis[i]=gap[i]=0;
        cur[i]=head[i];
    }
    int u,flow=0,aug=INF;
    gap[s]=nn;
    u=pre[s]=s;
    bool flag;
    while(dis[s]<nn)
    {
        flag=false;
        for(int &i=cur[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            if(edge[i].f>0&&dis[u]==dis[v]+1)
            {
                flag=1;
                if(edge[i].f<aug)
                    aug=edge[i].f;
                pre[v]=u;
                u=v;
                if(u==t)
                {
                    flow+=aug;
                    while(u!=s)
                    {
                        u=pre[u];
                        edge[cur[u]].f-=aug;
                        edge[cur[u]^1].f+=aug;
                    }
                    aug=INF;
                }
                break;
            }
        }
        if(flag)continue;
        int mindis=nn;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            if(dis[v]<mindis&&edge[i].f>0)
            {
                mindis=dis[v];
                cur[u]=i;
            }
        }
        if((--gap[dis[u]])==0) break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return flow;
}
int main()
{
    //freopen("in.txt","r",stdin);
    int t;
    string a,b;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        int s=0,e=m+7;
        nn=m+8;
        init();
        for(int i=1;i<=m;i++)
        {
            cin>>a>>b;
            int x=change(a),y=change(b);
            add_edge(s,i,1);
            add_edge(i,x,1);
            add_edge(i,y,1);
        }
        for(int i=1;i<=6;i++)
            add_edge(m+i,e,n/6);
        int ans=sap(s,e);
        if(ans>=m)cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

还可以用二分图做

#include <cstdio>  
#include <cstring>  
const int MAX = 300;  
int a[MAX][MAX];  
int Match[MAX];  
bool vis[MAX];  
char str[7][10] = {"XXL","XL","L","M","S","XS"};  
int n,m;  
  
int get(char *s)  
{  
    for(int i = 0;i < 6; i++)  
    {  
        if(strcmp(s,str[i]) == 0)  
        {  
            return i + 1;  
        }  
    }  
}  
  
bool dfs(int u)  
{  
    int i;  
    for(i = i;i <= m; i++)  
    {  
        if(!a[u][i])  
            continue;  
        if(vis[i])  
            continue;  
        vis[i] = true;  
        if(Match[i] == -1 || dfs(Match[i]))  
        {  
            Match[i] = u;  
            return true;  
        }  
    }  
    return false;  
}  
int match()  
{  
    int ret = 0;  
    int i;  
    memset(Match,-1,sizeof(Match));  
    for(i = 1;i <= n; i++)  
    {  
        memset(vis,false,sizeof(vis));  
        if(dfs(i))  
            ret++;  
    }  
    return ret;  
}  
int main()  
{  
    int t,i,j;  
    char s1[10];  
    char s2[10];  
    scanf("%d",&t);   
    while(t--)  
    {  
        scanf("%d %d",&n,&m);  
        memset(a,0,sizeof(a));  
        for(i = 1;i <= m; i++)  
        {  
            scanf("%s %s",s1,s2);  
            int id1 = get(s1);  
            int id2 = get(s2);  
            for(j = 0;j < n/6; j++)  
            {  
                a[id1+6*j][i] = 1;  
                a[id2+6*j][i] = 1;  
            }  
        }  
        if(match() == m)  
            puts("YES");  
        else  
            puts("NO");  
    }  
    return 0;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值