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
- hdu5352城市重建 (km,最大流,费用流)
- hdu5352 MZL's City(最小费用最大流问题)
- ACM hdu5352 最小费用最大流 模板 网络流
- hdu5352 MZL's City 网络流,最小费用最大流模板
- hdu 4862KM&最小费用最大流
- POJ 2516 Minimum Cost (最小费用最大流,KM解法)
- hdoj 3488 Tour 【最小费用最大流】【KM算法】
- HDU 3435 KM算法或者最小费用最大流
- poj2195 Going Home(费用流|KM)
- HDU 2426 Interesting Housing Problem 二分匹配(KM模板)或者最小费用最大流
- POJ 2195-Going Home(KM算法/最小费用最大流算法)
- 城市重建(网络流)
- HDOJ 3315 - My Brute 维护两个最值..构图最大费用最大流 or KM模板
- hdoj 2246 Interesting Housing Problem 【最大费用最大流 or KM算法】
- HDU 1533Going Home(KM算法求二分图最小权匹配或者最小费用最大流)
- poj 2195 Going Home(KM||费用流)
- hdu1853 Cyclic Tour (KM算法求最小费用流)
- 【HDU】 3395 Special Fish 费用流(可KM匹配)
- 【面试】Java Web
- 深入理解javascript原型和闭包(3)——prototype原型
- Python常用函数
- static 作用总结
- C语言学习:简单了解下stdlib中的字符串转换函数
- hdu5352城市重建 (km,最大流,费用流)
- [BZOJ2238]填表格
- 特征选取relief算法
- Nginx系列—location总结及rewrite规则写法
- Vases and Flowers HDU
- AlarmManager实现闹钟
- java集合TreeMap使用自然排序,定制排序
- 最大子段和的拓展
- 分数化小数 (decimal) 算法竞赛入门经典 第二版 习题 2-5