BZOJ2893:征服王(费用流)

Description

虽然春希将信息传递给了雪菜,但是雪菜却好像完全不认得春希了。心急如焚的春希打开了第二世代机能,对雪菜的脑内芯片进行了直连-hack。
进入到雪菜内部的春希发现(这什么玩意。。),雪菜的脑部结构被分成了n个块落,并且一些块落之间被有向边连接着。由于四分五裂的脑部,雪菜关于春希的记忆也完全消失,春希为了恋人,启动了inversionprocess.
在inversion process中,要想使雪菜回到正常状态,需要纳米机器人的帮助。纳米机器人可以从任意一个可以作为起点的块落出发进行修复,也可以在任意一个可以作为终点的块落结束修复(并不是到了某个终点就一定要停止)。春希希望所有的节点都能被修复(只要纳米机器人到过该点就算修复过),这样才能让雪菜重获新生。
作为纳米机器人1号的你能帮助春希算算至少需要多少个机器人才能拯救雪菜吗?
当然,如果无论如何都无法使得春希的愿望被满足的话,请输出”no solution”(不包括引号)

Input

题目包含多组数据
第1行有一个正整数t,表示数据的组数。
第2行有两个正整数n、m,a,b,分别表示块落的数量、有向边的数量、起点的数量、终点的数量。
第3行有a个正整数,表示可以作为起点的块落。
第4行有b个正整数,表示可以作为终点的块落。
第5行至第m+4行,每行有两个正整数u、v,表示能从编号为u的块落到编号为v的块落。
之后以此类推。

Output

输出共有t行,每行输出对应数据的答案。

Sample Input

2
2 1 1 1
1
2
2 1
3 2 3 3
1 2 3
1 2 3
1 2
1 3

Sample Output

no solution
2
【数据规模和约定】
对于30%的数据,满足n <= 10, m <= 100。
对于60%的数据,满足n <= 200, m <= 5000。
对于100%的数据,满足t<=10,n <= 1000, m <= 10000。

Solution

打死白学家

首先第一感觉这个题很像最小路径覆盖……但他并不是一个$DAG$。所以我们自己动手丰衣足食把它缩成一个$DAG$。

现在变成了一个多起点多终点的最小路径覆盖问题。我们首先把一个点拆成$u$和$u'$,并且$u$连向$u'$一条流量为$1$,费用为1的边。

然后原图的边就$u'$连向$v$一条流量为$INF$,费用为$0$的边。

源点$S$向图中的起点$s$连流量为$INF$,费用为$0$的边,终点$t'$向图中的汇点$E$流量为$INF$,费用为$0$的边。

跑一边最大费用最大流。如果费用为点数那么说明每个点都经过了,答案为增广次数。

否则无解。

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<queue>
  5 #define N (10009)
  6 using namespace std;
  7 
  8 struct Edge{int to,next,flow,cost;}edge[N*100];
  9 int DFN[N],Low[N],Stack[N],ID[N],Vis[N],top,dfs_num,id_num;
 10 int T,n,m,A,B,a[N],b[N],u[N*10],v[N*10],x,INF,s,e=10000;
 11 int dis[N],pre[N],vis[N];
 12 int head[N],num_edge;
 13 queue<int>q;
 14 
 15 void Clear()
 16 {
 17     memset(head,0,sizeof(head));
 18     memset(DFN,0,sizeof(DFN));
 19     memset(Low,0,sizeof(Low));
 20     memset(ID,0,sizeof(ID));
 21     memset(Vis,0,sizeof(Vis));
 22     num_edge=top=dfs_num=id_num=0;
 23 }
 24 
 25 void add(int u,int v,int l,int c)
 26 {
 27     edge[++num_edge].to=v;
 28     edge[num_edge].next=head[u];
 29     edge[num_edge].flow=l;
 30     edge[num_edge].cost=c;
 31     head[u]=num_edge;
 32 }
 33 
 34 bool SPFA(int s,int e)
 35 {
 36     memset(dis,0x7f,sizeof(dis));
 37     memset(pre,-1,sizeof(pre));
 38     dis[s]=0; q.push(s); vis[s]=1;
 39     while (!q.empty())
 40     {
 41         int x=q.front(); q.pop();
 42         for (int i=head[x]; i; i=edge[i].next)
 43             if (edge[i].flow && dis[x]+edge[i].cost<dis[edge[i].to])
 44             {
 45                 dis[edge[i].to]=dis[x]+edge[i].cost;
 46                 pre[edge[i].to]=i;
 47                 if (!vis[edge[i].to])
 48                 {
 49                     vis[edge[i].to]=1;
 50                     q.push(edge[i].to);
 51                 }
 52             }
 53         vis[x]=0;
 54     }
 55     return dis[e]!=INF;
 56 }
 57 
 58 void MCMF(int s,int e)
 59 {
 60     int fee=0,ans=0;
 61     while (SPFA(s,e))
 62     {
 63         if (dis[e]==0) break;
 64         else ans++;
 65         int d=INF;
 66         for (int i=e; i!=s; i=edge[((pre[i]-1)^1)+1].to)
 67             d=min(d,edge[pre[i]].flow);
 68         for (int i=e; i!=s; i=edge[((pre[i]-1)^1)+1].to)
 69         {
 70             edge[pre[i]].flow-=d;
 71             edge[((pre[i]-1)^1)+1].flow+=d;
 72         }
 73         fee+=d*dis[e];
 74     }
 75     if (-fee==id_num) printf("%d\n",ans);
 76     else puts("no solution");
 77 }
 78 
 79 void Tarjan(int x)
 80 {
 81     DFN[x]=Low[x]=++dfs_num;
 82     Stack[++top]=x; Vis[x]=1;
 83     for (int i=head[x]; i; i=edge[i].next)
 84         if (!DFN[edge[i].to])
 85         {
 86             Tarjan(edge[i].to);
 87             Low[x]=min(Low[x],Low[edge[i].to]);
 88         }
 89         else if (Vis[edge[i].to])
 90             Low[x]=min(Low[x],DFN[edge[i].to]);
 91     if (DFN[x]==Low[x])
 92     {
 93         ID[x]=++id_num; Vis[x]=0;
 94         while (Stack[top]!=x)
 95         {
 96             ID[Stack[top]]=id_num;
 97             Vis[Stack[top--]]=0;
 98         }
 99         top--;
100     }
101 }
102 
103 int main()
104 {
105     memset(&INF,0x7f,sizeof(INF));
106     scanf("%d",&T);
107     while (T--)
108     {
109         Clear();
110         scanf("%d%d%d%d",&n,&m,&A,&B);
111         for (int i=1; i<=A; ++i) scanf("%d",&a[i]);
112         for (int i=1; i<=B; ++i) scanf("%d",&b[i]);
113         for (int i=1; i<=m; ++i) scanf("%d%d",&u[i],&v[i]), add(u[i],v[i],0,0);
114         for (int i=1; i<=n; ++i) if (!DFN[i]) Tarjan(i);
115         memset(head,0,sizeof(head)); num_edge=0;
116         for (int i=1; i<=A; ++i)
117             add(s,ID[a[i]],INF,0), add(ID[a[i]],s,0,0);
118         for (int i=1; i<=B; ++i)
119             add(ID[b[i]]+5000,e,INF,0), add(e,ID[b[i]]+5000,0,0);
120         for (int i=1; i<=m; ++i)
121             if (ID[u[i]]!=ID[v[i]])
122                 add(ID[u[i]]+5000,ID[v[i]],INF,0), add(ID[v[i]],ID[u[i]]+5000,0,0);
123         for (int i=1; i<=id_num; ++i)
124         {
125             add(i,i+5000,1,-1); add(i+5000,i,0,1);
126             add(i,i+5000,INF,0); add(i+5000,i,0,0);
127         }
128         MCMF(s,e);
129     }
130 }
posted @ 2019-01-18 18:50  Refun  阅读(221)  评论(0编辑  收藏  举报