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 最小费用流 ||二分图匹配)
原文:http://blog.csdn.net/u014422052/article/details/47334955