Escape HDU - 3605 (最大流)(多重匹配)

本文介绍了一种使用网络流算法解决特定人数在不同行星上居住可能性的问题。通过优化算法减少时间复杂度,实现对大规模数据的有效处理。具体方法包括将具有相同居住偏好的人进行合并,并限制行星数量来降低计算复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2012 If this is the end of the world how to do? I do not know how. But now scientists have found that some stars, who can live, but some people do not fit to live some of the planet. Now scientists want your help, is to determine what all of people can live in these planets.
Input
More set of test data, the beginning of each data is n (1 <= n <= 100000), m (1 <= m <= 10) n indicate there n people on the earth, m representatives m planet, planet and people labels are from 0. Here are n lines, each line represents a suitable living conditions of people, each row has m digits, the ith digits is 1, said that a person is fit to live in the ith-planet, or is 0 for this person is not suitable for living in the ith planet.
The last line has m digits, the ith digit ai indicates the ith planet can contain ai people most..
0 <= ai <= 100000
Output
Determine whether all people can live up to these stars
If you can output YES, otherwise output NO.
Sample Input
1 1
1
1

2 2
1 0
1 0
1 1
Sample Output
YES
NO
这个题做了上一道,知道是用网络流的算法来解决了,就是按照正常思路来做了,后来发现超时了,我想一想,n这么大,我们每次增广的时候只能增广容量为1大小的值,也就是说n多大就要进行多次的bfs,后来想想某些人的对星球的选择意愿应该会相同,看到星球只有10个,那么最多只有210种意愿了,所有就是把某些相同选择的人的给压缩了,那么最多就是1024个人会和m个星球想练

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
int n,m;
struct node1
{
    int to;
    int cap;
}edge[25000];
int k;
vector<int> graph[2000];
int num[1030];
void addEdge(int x,int y,int c)
{
    edge[k].to=y;
    edge[k].cap=c;
    graph[x].push_back(k);
    k++;
    edge[k].to=x;
    edge[k].cap=0;
    graph[y].push_back(k);
    k++;
}
struct node
{
    int now;
    int lastIndex;
    int index;
    int minC;
}que[30000];
int head,tail;
bool vis[2000];
bool work()
{
    bool sign;
    int ans=0;
    node start;
    node endd;
    for(;;)
    {
        //cout<<"haha"<<endl;
        memset(vis,false,sizeof(vis));
        start.lastIndex=-1;
        start.now=0;
        start.minC=10000000;
        head=tail=0;
        que[tail++]=start;
        sign=true;
        vis[0]=true;
        while(head<tail&&sign)
        {
            node temp=que[head++];
            int u=temp.now;
            for(int i=0;i<graph[u].size();i++)
            {
                int index=graph[u][i];
                int v=edge[graph[u][i]].to;
                if(vis[v]||edge[index].cap==0)
                    continue;
                if(v==(1<<m)+m)
                {
                    endd.index=index;
                    endd.minC=min(edge[index].cap,temp.minC);
                    endd.lastIndex=head-1;
                    sign=false;
                    break;
                }
                else
                {
                    vis[v]=true;
                    node out;
                    out.now=v;
                    out.lastIndex=head-1;
                    out.index=index;
                    out.minC=min(edge[index].cap,temp.minC);
                    que[tail++]=out;
                }
            }
        }
        if(sign)
            break;
        else
        {
            int cal=endd.minC;
            ans+=cal;
            while(endd.lastIndex!=-1)
            {
                int index=endd.index;
                edge[index].cap-=cal;
                edge[index^1].cap+=cal;
                endd=que[endd.lastIndex];
            }
        }
    }
    //cout<<ans<<endl;
    //cout<<total<<endl;
    return ans==n;
}
int main()
{
   int a,b;
   while(scanf("%d%d",&n,&m)==2)
   {
       for(int i=0;i<=(1<<m)+m;i++)
            graph[i].clear();
        memset(num,0,sizeof(num));
       k=0;
       int p=(1<<m)+m;
       int state;
       for(int i=1;i<=n;i++)
       {
           state=0;
           for(int j=0;j<m;j++)
           {
                scanf("%d",&b);
                if(b)
                    state+=1<<j;//译码
           }
           num[state]++;
       }
       //cout<<"p:"<<p<<endl;
       for(int s=1;s<(1<<m);s++)
       {
           if(num[s])
           {
               addEdge(0,s,num[s]);
               for(int i=0;i<m;i++)
                if((s>>i)&1)//解码
                   addEdge(s,(1<<m)+i,num[s]);

           }
       }
       for(int i=1;i<=m;i++)
       {
           scanf("%d",&b);
           addEdge((1<<m)-1+i,p,b);
       }
       if(work())
        printf("YES\n");
       else
        printf("NO\n");
   }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值