标签:mzls city hdu 5352 最小费用流 二分图匹配
1 5 6 2 2 1 2 2 1 3 1 1 1 2 3 1 1 2 1 2
3 0 2 1HintNo city was rebuilt in the third year,city 1 and city 3 were rebuilt in the fourth year,and city 2 was rebuilt in the sixth year.
题意:有n个城市m年前被地震摧毁,道路也被破坏了,m年间进行了一些城市和道路的重建,有三种操作:
(1)1 u表示重建u或者与u直接相连或间接相连的城市;
(2)2 u v表示在城市u和v之间建一条道路;
(3)3表示发生地震破坏了哪些道路。
每年最多重建K个城市,城市一旦重建就不会再被地震摧毁,问这m年后总共重建的城市数目最大为多少,并按照字典序输出每年建造的城市数目。
思路:起初只知道要倒着来,具体怎么弄没想出来,看了题解是用二分图匹配,这是我第一次遇到把操作当做节点的,太弱,还是题目做少了=-=。但感觉费用流更简单,先讲讲费用流的做法。
把重建城市的操作当成一个节点 i ,添加源点和汇点,源点向 i 连边,容量为K,因为要控制字典序输出,所以越靠前的费用越大,然后i向其他连通的城市连边,容量为1 ,费用为0,每个城市向汇点连边,容量为1 ,费用为0 。跑完费用流后流量就是重建城市的最大数目,然后与源点相连的边上的流量就是每年要重建的城市数,依次输出即可。
代码:
//最小费用流 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #pragma comment (linker,"/STACK:102400000,102400000") #define mod 1000000009 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define FRE(i,a,b) for(i = a; i <= b; i++) #define FRL(i,a,b) for(i = a; i < b; i++) #define mem(t, v) memset ((t) , v, sizeof(t)) #define sf(n) scanf("%d", &n) #define sff(a,b) scanf("%d %d", &a, &b) #define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c) #define pf prllf #define DBG pf("Hi\n") const int maxn = 202; const int MAXN = 1010; const int MAXM = 2000000; typedef __int64 ll; using namespace std; int n,m,K,cnt; int mp[maxn][maxn],node[500][maxn]; bool VIS[maxn]; struct Edge { int to,next,cap,flow,cost; }edge[MAXM]; int head[MAXN],tol,tot; int pre[MAXN],dis[MAXN]; bool vis[MAXN]; int N; void init() { tol=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int cap,int cost) { edge[tol].to=v; edge[tol].cap=cap; edge[tol].cost=cost; edge[tol].flow=0; edge[tol].next=head[u]; head[u]=tol++; edge[tol].to=u; edge[tol].cap=0; edge[tol].cost=-cost; edge[tol].flow=0; edge[tol].next=head[v]; head[v]=tol++; } bool spfa(int s,int t) { queue<int>q; for (int i=0;i<N;i++) { dis[i]=INF; vis[i]=false; pre[i]=-1; } dis[s]=0; vis[s]=true; q.push(s); while (!q.empty()) { int u=q.front(); q.pop(); vis[u]=false; for (int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) { dis[v]=dis[u] + edge[i].cost; pre[v]=i; if (!vis[v]) { vis[v]=true; q.push(v); } } } } if (pre[t]==-1) return false; else return true; } //返回的是最大流,cost存的是最小费用 int minCostMaxflow(int s,int t,int &cost) { int flow=0; cost=0; while (spfa(s,t)) { int Min=INF; for (int i=pre[t];i!=-1;i=pre[edge[i^1].to]) { if (Min > edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow; } for (int i=pre[t];i!=-1;i=pre[edge[i^1].to]) { edge[i].flow+=Min; edge[i^1].flow-=Min; cost+=edge[i].cost*Min; } flow+=Min; } return flow; } void dfs(int u) { VIS[u]=true; node[cnt][tot++]=u; for (int v=1;v<=n;v++) if (!VIS[v]&&mp[u][v]) dfs(v); } int main() { int i,j,t,u,v,op,cc; scanf("%d",&t); while (t--) { scanf("%d%d%d",&n,&m,&K); memset(mp,0,sizeof(mp)); init();cnt=0; cc=500; for (i=0;i<m;i++) { scanf("%d",&op); if (op==1) { scanf("%d",&u); memset(VIS,false,sizeof(VIS)); tot=1; ++cnt; dfs(u); node[cnt][0]=tot-1; addedge(0,cnt+n,K,cc); cc--; } else if (op==2) { scanf("%d%d",&u,&v); mp[u][v]=mp[v][u]=1; } else { int xx; scanf("%d",&xx); while (xx--) { scanf("%d%d",&u,&v); mp[u][v]=mp[v][u]=0; } } } N=n+cnt+2; for (i=1;i<=cnt;i++) { for (j=1;j<=node[i][0];j++) addedge(i+n,node[i][j],1,0); } for (i=1;i<=n;i++) addedge(i,cnt+n+1,1,0); int ans,cost; ans=minCostMaxflow(0,n+cnt+1,cost); printf("%d\n",ans); printf("%d",edge[0].flow); for (i=2;i<2*cnt;i+=2) printf(" %d",edge[i].flow); printf("\n"); } }
代码:
//二分图 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #pragma comment (linker,"/STACK:102400000,102400000") #define mod 1000000009 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define FRE(i,a,b) for(i = a; i <= b; i++) #define FRL(i,a,b) for(i = a; i < b; i++) #define mem(t, v) memset ((t) , v, sizeof(t)) #define sf(n) scanf("%d", &n) #define sff(a,b) scanf("%d %d", &a, &b) #define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c) #define pf prllf #define DBG pf("Hi\n") const int maxn = 202; const int MAXN = 100010; const int MAXM = 2000000; typedef __int64 ll; using namespace std; struct Edge { int u,v,next; }edge[MAXM]; int linker[maxn]; bool used[maxn]; int num,head[MAXN],ans[maxn]; int mp[maxn][maxn]; int node[maxn];//存与u连通的点 bool vis[maxn]; int n,m,K,cnt,tot; void init() { num=0; for (int i=0;i<=m*K;i++) head[i]=-1; } void addedge(int u,int v) { edge[num].u=u; edge[num].v=v; edge[num].next=head[u]; head[u]=num++; } bool dfs(int u) { for (int i=head[u];~i;i=edge[i].next) { int v=edge[i].v; if (!used[v]) { used[v]=true; if (linker[v]==-1||dfs(linker[v])) { linker[v]=u; return true; } } } return false; } int hungary() { int res=0; memset(linker,-1,sizeof(linker)); memset(ans,0,sizeof(ans)); for (int i=cnt-1;i>=0;i--) { for (int j=i*K;j<i*K+K;j++) { memset(used,false,sizeof(used)); if (dfs(j)) { res++; ans[i]++; } } } return res; } void DFS(int u) { vis[u]=true; node[tot++]=u; for (int v=1;v<=n;v++) if (!vis[v]&&mp[u][v]) DFS(v); } int main() { int i,j,k,t,op,u,v; scanf("%d",&t); while (t--) { scanf("%d%d%d",&n,&m,&K); init(); memset(mp,0,sizeof(mp)); cnt=0; //记录操作1的个数 for (i=0;i<m;i++) { scanf("%d",&op); if (op==1) { scanf("%d",&u); memset(vis,false,sizeof(vis)); tot=0; DFS(u); //dfs搜索与u连通的点并存在node数组内 for (j=cnt*K;j<cnt*K+K;j++) { for (k=0;k<tot;k++) addedge(j,node[k]); } cnt++; } else if (op==2) { scanf("%d%d",&u,&v); mp[u][v]=mp[v][u]=1; } else { int xx; scanf("%d",&xx); while (xx--) { scanf("%d%d",&u,&v); mp[u][v]=mp[v][u]=0; } } } printf("%d\n",hungary()); printf("%d",ans[0]); for (i=1;i<cnt;i++) printf(" %d",ans[i]); printf("\n"); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
MZL's City (hdu 5352 最小费用流 ||二分图匹配)
标签:mzls city hdu 5352 最小费用流 二分图匹配
原文地址:http://blog.csdn.net/u014422052/article/details/47334955