HDU -- 3605 Escape(最大流 状态合并判满流)

来源:互联网 发布:淘宝退款申请撤销不了 编辑:程序博客网 时间:2024/06/04 18:16

题目大意:

有n个人,m个星球,对每个人来说,每个星球的选取状态可以使选或者不选,每个星球最多住的人数是一定的,问能否所有人都居住在星球上;

思路分析:

最大流判满流,但由于n太大,直接建图最后会超时;

①:一种建图方式是:星球最多有10个,所以每个人对于所有星球最多有2^10个状态,也就是1024个,这样我们就是把十万个点缩成了1024个点,然后我们把相同状态的点进行合并,设立一源点,让源点连向这些状态点,权值为该状态下的人数;设立一个汇点,让所有的星球连向汇点,权值为该星球可居住的人数;最后在状态和在该状态下可以选择的星球之间连边,权值为该状态下的人数,时间为904ms(加了输入外挂);

②:另一种建图的方法也是把相同的状态合并,不过此时使用map存储的每一种状态而已,时间为624ms;

代码实现:

二进制:

#include<cstdio>#include<cstring>#include<queue>#include<iostream>#define Max(a,b) ((a)>(b)?(a):(b))//#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;const int N=2000;const int M=325600;const int INF=0x3f3f3f3f;int n,m,s,t,top,head[N],gap[N],cur[N],pre[N],dis[N],state[N],vis[N];struct Edge{    int to,next,flow;}edge[M];void Addedge(int from,int to,int val){    edge[top].to=to,edge[top].next=head[from],edge[top].flow=val,head[from]=top++;    edge[top].to=from,edge[top].next=head[to],edge[top].flow=0,head[to]=top++;}void Bfs(){    queue<int> q;    memset(gap,0,sizeof(gap));    memset(dis,-1,sizeof(dis));    memset(vis,0,sizeof(vis));    gap[0]=1,dis[t]=0;    q.push(t);    vis[t]=1;    while(!q.empty()){        int u=q.front();        q.pop();        for(int i=head[u];i+1;i=edge[i].next){            if(vis[edge[i].to]==0&&dis[edge[i].to]==-1){                dis[edge[i].to]=dis[u]+1;                gap[dis[edge[i].to]]++;                q.push(edge[i].to);                vis[edge[i].to]=1;            }        }    }}int Sap(){    Bfs();    memset(pre,-1,sizeof(pre));    for(int i=0;i<=t;++i) cur[i]=head[i];    int u=s,i,cur_flow,max_flow=0,neck,tmp;    while(dis[s]<=t){        if(u==t){            cur_flow=INF;            for(int i=s;i!=t;i=edge[cur[i]].to){                if(cur_flow>edge[cur[i]].flow){                    neck=i;                    cur_flow=edge[cur[i]].flow;                }            }            for(int i=s;i!=t;i=edge[cur[i]].to){                tmp=cur[i];                edge[tmp].flow-=cur_flow;                edge[tmp^1].flow+=cur_flow;            }            max_flow+=cur_flow;            u=neck;        }        int i;        for(i=cur[u];i!=-1;i=edge[i].next)            if(edge[i].flow&&dis[u]==dis[edge[i].to]+1) break;        if(i!=-1){            cur[u]=i;            pre[edge[i].to]=u;            u=edge[i].to;        }else{            if(--gap[dis[u]]==0) break;            cur[u]=head[u];            int mindis=t;            for(i=head[u];i!=-1;i=edge[i].next){                if(edge[i].flow&&mindis>dis[edge[i].to])                    mindis=dis[edge[i].to];            }            dis[u]=mindis+1;            gap[dis[u]]++;            if(u!=s) u=pre[u];        }    }    return max_flow;}template<class T>inline bool Read(T &n){    T x=0;    char c=getchar();    while((c<'0'||c>'9')&&c!=EOF) c=getchar();    if(c==EOF) return false;    while(c>='0'&&c<='9') x*=10,x+=(c-'0'),c=getchar();    n=x;    return true;}int main(){    while(Read(n)&&Read(m)){        memset(head,-1,sizeof(head));        memset(state,0,sizeof(state));        int f,tmp=(1<<m);        top=0,s=tmp+m,t=s+1;        for(int i=1;i<=n;++i){             int sum=0;             for(int j=1;j<=m;++j){                Read(f);                sum=(sum<<1)+f;             }             state[sum]++;//记录这种状态下的状态数;        }        for(int i=0;i<tmp;++i){            Addedge(s,i,state[i]);// 源点连向每一种状态;            int z=i;            int cnt=0;            while(z){                if(z&1) Addedge(i,cnt+tmp,state[i]);//在这个状态下可以选cnt对应的星球,就连边;                z=z>>1;                cnt++;            }        }        for(int i=0;i<m;++i){            Read(f);            Addedge(tmp+i,t,f);// 每一个星球连向汇点;        }        int res=Sap();        if(res==n) printf("YES\n");        else printf("NO\n");    }}


map建图:

map<string,int> mp;map<string,int>::iterator ite;。。。。。。int main(){    while(~scanf("%d%d",&n,&m)){        memset(head,-1,sizeof(head));        top=0;        mp.clear();        getchar();        char st[N];        for(int i=0;i<n;++i){            gets(st);            string str=st;            mp[st]++;        }        for(int i=0;i<m;++i) scanf("%d",&num[i]);        s=0,t=mp.size()+m+1;        int i;        for(ite=mp.begin(),i=1;ite!=mp.end();++ite,++i){            Addedge(s,i,ite->second);            int tmp=1;            for(int j=0;j<ite->first.size();++j){                if(ite->first[j]=='1')                    Addedge(i,mp.size()+tmp,ite->second);                if(ite->first[j]=='0'||ite->first[j]=='1') tmp++;            }        }        for(int i=0;i<m;++i) Addedge(i+mp.size()+1,t,num[i]);        int res=Sap();        if(res>=n) printf("YES\n");        else printf("NO\n");    }}






0 0
原创粉丝点击