HDU - 3605 Escape 状态压缩最大流

题目链接

https://vjudge.net/problem/HDU-3605

题意

n个人(范围10w),m个星球(范围10),每个人有对星球的不同喜好,每个星球有自己的容量,问能否让所有人都在满意的星球上?

思路

一眼就是最大流(二分匹配我没学。。),朴素做法s向人连边权1,人向感兴趣星球连边权1,星球向t连边权为容量,跑dinic,一遍TLE,芜湖~

之前学网络流的时候知道Dinic上界很糟糕,但是大部分题不卡,今天一查才知道上界是O(V²E),换了ISAP的板子也不行,百度一下得知需要状态压缩。

最多只有10个星球,那么对星球的喜好也就最多只有1024种组合。最多10w人,他们除了喜好不同外,没有任何别的信息,所以完全可以用组合代替人做节点。先统计不同状态的人数,s向状态连边,权为状态人数,状态向星球连边,权为人数,星球向t连边,权容量,这样就能将V从1e5压缩到1e3,E也从1e6到了1e4的级别。

时限2s,状压Dinic跑了1.2s。

代码

#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
using namespace std;
	typedef long long ll;
	const int inf=0x3f3f3f3f;
	const int maxn=100100;
	const int maxe=2500010;

	int head[maxn],cnt;
	struct Edge{
    
    
		int v;
		int w;
		int next;
	}edge[maxe];

	int n,m,s,t;
	ll maxflow;
	int deep[maxn];
	int now[maxe];


	void init(){
    
    
		memset(head,-1,sizeof(head));
		cnt=0;
		maxflow=0; 
		return ;	
	}
	void add(int u,int v,int w){
    
    
  		//cout<<u<<" "<<v<<" "<<w<<endl;
		edge[cnt].v=v;
		edge[cnt].w=w;
		edge[cnt].next=head[u];
		head[u]=cnt++;
	}

	inline bool bfs(){
    
    
    	memset(deep,0x3f,sizeof(deep));
    	queue<int>q;
    	q.push(s);deep[s] = 0;now[s] = head[s];
    	while(q.size()){
    
    
        	int x = q.front();q.pop();
        	for(int i=head[x];i!=-1;i=edge[i].next){
    
    
        	    int y=edge[i].v;
         	    if(edge[i].w>0&&deep[y]==inf){
    
    
         	    	q.push(y);
        	        now[y]=head[y];
         	       	deep[y]=deep[x]+1;
        	        if(y==t)	return 1;
				}
        	}
    	}
    	return 0;
	}

	ll dfs(int x,int flow){
    
    
    	if(x==t)	return flow;
    	ll ans = 0,k,i;
    	for(i=now[x];i!=-1&&flow;i=edge[i].next){
    
    
        	now[x]=i;
        	int y=edge[i].v;
        	if(edge[i].w>0&&(deep[y]==deep[x]+1)){
    
    
        	    k=dfs(y,min(flow,edge[i].w));
         		if(!k)	deep[y]=inf;
            	edge[i].w-=k;
            	edge[i^1].w+=k;
            	ans+=k;
            	flow-=k;
        	}
    	}
    	return ans;
	}	

	void dinic(){
    
    
    	while(bfs())
    	    maxflow+=dfs(s,inf);
	}
	int sta[5000];
	int main(){
    
    	
		while(scanf("%d%d",&n,&m)==2){
    
    
			memset(sta,0,sizeof sta);
			s=5000,t=s+1;
			init();
			for(int i=1;i<=n;i++){
    
    
				int tmp=0,fg;
				for(int j=1;j<=m;j++){
    
    
					scanf("%d",&fg);
					if(fg){
    
    
						tmp|=(1<<(j-1));
					}
				}
				sta[tmp]++;
			}
			for(int i=1;i<(1<<m);i++){
    
    
				if(sta[i]){
    
    
					add(s,i,sta[i]);
					add(i,s,0);
					for(int j=1;j<=m;j++){
    
    
						if(i&(1<<(j-1))){
    
    
							add(i,2000+j,sta[i]);
							add(2000+j,i,0);
						}
					}
				}
			}
			for(int i=1;i<=m;i++){
    
    
				int w;
				scanf("%d",&w);
				add(2000+i,t,w);
				add(t,2000+i,0);
			}
			dinic();
			if(maxflow==n)
				printf("YES\n");
			else
				printf("NO\n");
		}
    	return 0;
	}

猜你喜欢

转载自blog.csdn.net/TheSunspot/article/details/108359993
今日推荐