hdu5352 2015多校第5场 网络流(或二分图)
来源:互联网 发布:linux查看内存型号 编辑:程序博客网 时间:2024/05/20 02:52
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5352
题意:有N个城市,一开始都处于被地震摧毁的状态。之后有M个询问,1 x表示可以将与x相连(包括x)的城市重建(重建后不再被地震破坏),每次能重建的城市的数量小于等于k;2 x y表示在x和y之间建立一条道路相同;3 p x1 y1...xp yp表示有p组道路被破坏,分别是x1 y1...xp yp;现要求每次询问1 x时要重建几座城市,使得所有最后重建的城市的数量最多,且重建城市的数量形成的序列的字典序最小。
想法:
感觉是挺难想到的网络流问题,主要就是模型的确立(网络流难的一般都是建立模型)。
大致的建图方式:将所有城市与源点s相连,边的容量为1(为什么为1?因为城市只能被重建一次,建好后便不会被摧毁),费用为0。将所有1 x的操作弄成节点与汇点t相连,容量为k(因为每次最多只能重建k个城市),费用为0。并且每次1 x的操作中,将该节点和x联通的节点都连一条边,边的容量为无穷大,边的费用是cost(这个等下稍微要有点技巧),就相当于每次的1 x的操作要重建几座城市。
如果题目要求是的最多建立几座城市,那么最大流就够了,但是这里要用到最小费用最大流来实现字典序最小。假设cost一开始是一个较大的值,每次操作1 x之后这个cost就自减一个值,这样做的目的是让流量优先通过后面操作的1 x,来实现字典序的最小。要输出答案的话,只要遍历1 x的节点,将通向汇点的边的流量记录下来输出就是最小字典序
#include<bits/stdc++.h>#define mem(a,b) memset(a,b,sizeof(a))#define FOR(i,a,b) for(int i = a;i <= b;i++)using namespace std;typedef long long ll;const int INF = 0x3f3f3f3f;const int e_maxn = 150000 * 2;const int v_maxn = 900;struct ppp{ int v,nex,cap,flow,c;}e[e_maxn];int head[v_maxn],pre[v_maxn],inq[v_maxn],a[v_maxn],dis[v_maxn];int tole,N,M,s,t,K;void make_edge(int u,int v,int cap,int c){ e[tole].v = v;e[tole].cap = cap;e[tole].c = c;e[tole].flow = 0;e[tole].nex = head[u]; head[u] = tole++;}void add_edge(int u,int v,int cap,int c){ make_edge(u,v,cap,c); make_edge(v,u,0,-c);}queue<int> que;void maxflow_mincost(int s,int t,int &flow,int &cost){ int temp,v,u; while(1) { mem(inq,0); mem(dis,0x3f); a[s] = INF; dis[s] = 0; inq[s] = 1; que.push(s); mem(pre,-1); pre[s] = 0; while(!que.empty()) { temp = que.front(); que.pop(); inq[temp] = 0; for(int i = head[temp];~i;i = e[i].nex) { v = e[i].v; if(e[i].cap > e[i].flow && dis[v] > dis[temp] + e[i].c) { dis[v] = dis[temp] + e[i].c; pre[v] = i; a[v] = min(a[temp],e[i].cap - e[i].flow); if(!inq[v]){que.push(v);inq[v] = 1;} } } } if(pre[t] == -1)break; flow += a[t]; cost += dis[t] * a[t]; for(u = t;u != s;u = e[pre[u] ^ 1].v) { e[pre[u]].flow += a[t]; e[pre[u] ^ 1].flow -= a[t]; } }}int ma[202][202];int vis_v[202];void dfss(int u)//找于x相连的点用dfs{ for(int i = 1; i <= N;i++) if(!vis_v[i] && ma[u][i]) { vis_v[i] = 1; dfss(i); }}int main(){ int T; scanf("%d",&T); while(T--) { mem(head,-1); tole = 0; scanf("%d%d%d",&N,&M,&K); int cntk = 0; mem(ma,0); int a,b,c; int cost = 9999999;//cost在每次1 x的操作后自减 while(M--) { scanf("%d",&a); if(a == 1){ scanf("%d",&b); mem(vis_v,0); vis_v[b] = 1; dfss(b); cntk++; for(int i = 1;i <= N;i++) if(vis_v[i]) add_edge(i,N + cntk,INF,cost); cost -= 100; }else if(a == 2){ scanf("%d%d",&b,&c); ma[b][c] = 1; ma[c][b] = 1; }else if(a == 3){ scanf("%d",&a); for(int i = 1;i <= a;i++) { scanf("%d%d",&b,&c); ma[b][c] = ma[c][b] = 0; } } } s = 0,t = N + cntk + 1; for(int i = 1;i <= N;i++) add_edge(s,i,1,0); for(int i = N + 1;i <= N + cntk;i++) add_edge(i,t,K,0); int haha = 0,xixi = 0; maxflow_mincost(s,t,haha,xixi); int ans[505]; int len = 0; int summ = 0; for(int i = N + 1;i <= N + cntk;i++) { for(int j = head[i];~j;j = e[j].nex) { int v = e[j].v; if(v == t) { summ += e[j].flow; ans[len++] = e[j].flow; break; } } } printf("%d\n",summ); for(int i = 0;i < len;i++) { if(i > 0){ printf(" "); } printf("%d",ans[i]); } printf("\n"); }}
0 0
- hdu5352 2015多校第5场 网络流(或二分图)
- ACM hdu5352 最小费用最大流 模板 网络流
- hdu5352城市重建 (km,最大流,费用流)
- hdu5352 MZL's City(最小费用最大流问题)
- hdu5352 MZL's City 网络流,最小费用最大流模板
- bzoj1059: [ZJOI2007]矩阵游戏(网络流 或 二分图匹配)[省选计划系列]
- poj 3614 Sunscreen 网络流或二分图多重匹配或优先队列
- 二分图最佳匹配(网络流)
- POJ1087(网络流,二分图匹配)
- hdu5855(2016多校第9场,二分,最大权闭合图,最大流)
- 网络流|二分图+uva11045
- 网络流+二分图总结
- [网络流] 二分图匹配
- 网络流&二分图 12
- poj2112(二分网络流)
- hdu 5093 最大流或二分图
- 【网络流24题】试题库(二分图+最大流)
- Tour(二分图最大权匹配)(网络流)
- 晚上好,终于有一个自己的博客
- VIJOS-P1144 小胖守皇宫(树形dp)
- C++ 浅谈C++中指针和引用
- nohup失效,关闭putty后无法在后台运行
- gpp完美解锁
- hdu5352 2015多校第5场 网络流(或二分图)
- POJ-2488 A Knight's Journey
- MFC中通过子窗口关闭父窗口以实现退出程序
- 是孝道的继承,还是无耻的升级
- Day8.05
- Spring缓存注解@Cache使用
- Sphinx和Coreseek:强大的开源全文检索引擎
- Swift 表达正则表达式-手机-邮箱-密码
- 通过父元素和子元素的class类,获取该同类子元素的数组