hdu5352城市重建 (km,最大流,费用流)

来源:互联网 发布:excel怎么剔除重复数据 编辑:程序博客网 时间:2024/06/06 14:07

题意:略

题解:一道将自己隐藏得很好的匹配问题,直接说建图方法吧(按照网络流的方式叙述的,想写km的可以自行转换)

对于N座城市,每座城市都看做一个点,并直接与源点相连,容量为1,对于操作1,将其看做一个点,将此时在联通

块中的点均与其相连,容量为1,然后再将其与汇点相连,容量为k(km的话,这里就需要加k个点了,所以跑得并没有

网络流快)对于2,3操作,就是就按照它所说删边加边就是了

因为要按字典序拍序,于是可以转成费用流,越靠后的点费用越小(解释得有点模糊,详见代码)

这里只有费用流代码,km又麻烦又慢,不想写,费用流虽然看着有点长,但大多都是版

code:

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>#include<queue> const int inf=0x3f3f3f3f;const int MAXN=2000+5;const int MAXM=2000+5;const int MAXK=2000+5;using namespace std;struct node{    int c,next,e,cost;}h[MAXM*MAXN];int fir[MAXN+MAXM],cnt=1,ans,N,K;bool inq[MAXN+MAXM],vis[MAXN+MAXM];int dis[MAXN],source,target,year;queue<int> Q; int temp[MAXN],acnt;bool Map[MAXN][MAXN],flag[MAXN]; inline void addedge(int t1,int t2,int c,int cost){    h[++cnt].e=t2;    h[cnt].next=fir[t1];    h[cnt].c=c; h[cnt].cost=cost;    fir[t1]=cnt;     h[++cnt].e=t1;    h[cnt].next=fir[t2];    h[cnt].cost=-cost;    fir[t2]=cnt;}void dfs(int s){    flag[s]=1; addedge(s+1,year+N+1,1,-year);    for(int i=1;i<=N;i++)        if(Map[s][i]&&!flag[i]) dfs(i);}inline bool spfa(){    Q.push(target);    memset(dis,0x3f,sizeof dis);    dis[target]=0; inq[target]=1;    while(!Q.empty())    {        int s=Q.front(); Q.pop();        inq[s]=0;        for(int i=fir[s];i;i=h[i].next)        {            int e=h[i].e;            if(h[i^1].c<=0) continue;            if(dis[e]>dis[s]+h[i^1].cost)            {                dis[e]=dis[s]+h[i^1].cost;                if(!inq[e])                    Q.push(e),inq[e]=1;            }        }    }    if(dis[source]==dis[0]) return 0;    else return 1;}int aug(int s,int augco){    if(s==target)    {        ans+=dis[source]*augco;        return augco;    }    int delta,augc=augco;    for(int i=fir[s];i&&augc>0;i=h[i].next)    {        int e=h[i].e;        if(vis[e]||h[i].c<=0) continue;        if(dis[s]==dis[e]+h[i].cost)        {            vis[e]=1;            delta=min(h[i].c,augc);            delta=aug(e,delta);            h[i].c-=delta;            h[i^1].c+=delta;            augc-=delta;        }    }    return augco-augc;}int costflow(){    ans=0; int flow=0;    while(spfa())    {        memset(vis,0,sizeof vis);        vis[source]=1; flow+=aug(source,inf);    }    return flow;}inline void Clear(){    cnt=1; acnt=year=0;    memset(Map,0,sizeof Map);    memset(fir,0,sizeof fir);    memset(h,0,sizeof h);    memset(temp,0,sizeof temp);}int T,M,opt,x,y,q;int main(){    scanf("%d",&T);    while(T--)    {        Clear();        scanf("%d%d%d",&N,&M,&K);        for(int i=1;i<=M;i++)        {            scanf("%d",&opt);            switch(opt)            {                case 1:                    scanf("%d",&x);                    year++; dfs(x);                    memset(flag,0,sizeof flag);                break;                case 2:                    scanf("%d%d",&x,&y);                    Map[x][y]=Map[y][x]=1;                break;                case 3:                    scanf("%d",&q);                    while(q--)                    {                        scanf("%d%d",&x,&y);                        Map[x][y]=Map[y][x]=0;                    }                break;            }        }        target=year+N+2; source=1;        for(int i=1;i<=year;i++)            addedge(i+N+1,target,K,0);        for(int i=1;i<=N;i++) addedge(1,i+1,1,0);        printf("%d\n",costflow());        for(int i=fir[target];i;i=h[i].next)            temp[++acnt]=h[i].c;        for(int i=acnt;i;i--)            if(i!=1) printf("%d ",temp[i]);            else printf("%d\n",temp[i]);    }}/*n 1000m 1000k 1000这道题呢,到是有点思路,最开始,先把输入离线下来然后看,对于1操作,将k个城市拆成k个点,将处于该联通块内的每个城市都与这k个点相连,权值为这座城市出现的次数至于加边加点的操作,用矩阵应该比较方便吧,或者把所有联通块都给存下来?只是这个建图方法:将源点与所有N座城市均连一条边,容量为1,费用为0对于每次1操作,将所有联通块内的节点与该年连边,容量为1,费用为之前进行了几次1操作的数量取负,即越靠后的费用越小最后,把所有年份与汇点连边,容量为K,费用为015 6 22 1 22 1 31 11 23 1 1 21 2*/


阅读全文
0 0