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

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define N (10009)
using namespace std; struct Edge{int to,next,flow,cost;}edge[N*];
int DFN[N],Low[N],Stack[N],ID[N],Vis[N],top,dfs_num,id_num;
int T,n,m,A,B,a[N],b[N],u[N*],v[N*],x,INF,s,e=;
int dis[N],pre[N],vis[N];
int head[N],num_edge;
queue<int>q; void Clear()
{
memset(head,,sizeof(head));
memset(DFN,,sizeof(DFN));
memset(Low,,sizeof(Low));
memset(ID,,sizeof(ID));
memset(Vis,,sizeof(Vis));
num_edge=top=dfs_num=id_num=;
} void add(int u,int v,int l,int c)
{
edge[++num_edge].to=v;
edge[num_edge].next=head[u];
edge[num_edge].flow=l;
edge[num_edge].cost=c;
head[u]=num_edge;
} bool SPFA(int s,int e)
{
memset(dis,0x7f,sizeof(dis));
memset(pre,-,sizeof(pre));
dis[s]=; q.push(s); vis[s]=;
while (!q.empty())
{
int x=q.front(); q.pop();
for (int i=head[x]; i; i=edge[i].next)
if (edge[i].flow && dis[x]+edge[i].cost<dis[edge[i].to])
{
dis[edge[i].to]=dis[x]+edge[i].cost;
pre[edge[i].to]=i;
if (!vis[edge[i].to])
{
vis[edge[i].to]=;
q.push(edge[i].to);
}
}
vis[x]=;
}
return dis[e]!=INF;
} void MCMF(int s,int e)
{
int fee=,ans=;
while (SPFA(s,e))
{
if (dis[e]==) break;
else ans++;
int d=INF;
for (int i=e; i!=s; i=edge[((pre[i]-)^)+].to)
d=min(d,edge[pre[i]].flow);
for (int i=e; i!=s; i=edge[((pre[i]-)^)+].to)
{
edge[pre[i]].flow-=d;
edge[((pre[i]-)^)+].flow+=d;
}
fee+=d*dis[e];
}
if (-fee==id_num) printf("%d\n",ans);
else puts("no solution");
} void Tarjan(int x)
{
DFN[x]=Low[x]=++dfs_num;
Stack[++top]=x; Vis[x]=;
for (int i=head[x]; i; i=edge[i].next)
if (!DFN[edge[i].to])
{
Tarjan(edge[i].to);
Low[x]=min(Low[x],Low[edge[i].to]);
}
else if (Vis[edge[i].to])
Low[x]=min(Low[x],DFN[edge[i].to]);
if (DFN[x]==Low[x])
{
ID[x]=++id_num; Vis[x]=;
while (Stack[top]!=x)
{
ID[Stack[top]]=id_num;
Vis[Stack[top--]]=;
}
top--;
}
} int main()
{
memset(&INF,0x7f,sizeof(INF));
scanf("%d",&T);
while (T--)
{
Clear();
scanf("%d%d%d%d",&n,&m,&A,&B);
for (int i=; i<=A; ++i) scanf("%d",&a[i]);
for (int i=; i<=B; ++i) scanf("%d",&b[i]);
for (int i=; i<=m; ++i) scanf("%d%d",&u[i],&v[i]), add(u[i],v[i],,);
for (int i=; i<=n; ++i) if (!DFN[i]) Tarjan(i);
memset(head,,sizeof(head)); num_edge=;
for (int i=; i<=A; ++i)
add(s,ID[a[i]],INF,), add(ID[a[i]],s,,);
for (int i=; i<=B; ++i)
add(ID[b[i]]+,e,INF,), add(e,ID[b[i]]+,,);
for (int i=; i<=m; ++i)
if (ID[u[i]]!=ID[v[i]])
add(ID[u[i]]+,ID[v[i]],INF,), add(ID[v[i]],ID[u[i]]+,,);
for (int i=; i<=id_num; ++i)
{
add(i,i+,,-); add(i+,i,,);
add(i,i+,INF,); add(i+,i,,);
}
MCMF(s,e);
}
}

BZOJ2893:征服王(费用流)的更多相关文章

  1. BZOJ2893: 征服王

    题解: 裸的上下界最小流是有问题的.因为在添加了附加源之后求出来的流,因为s,t以及其它点地位都是平等的.如果有一个流经过了s和t,那么总可以认为这个流是从s出发到t的满足题意的流. 既然可能存在s到 ...

  2. 【BZOJ-2893】征服王 最大费用最大流(带下界最小流)

    2893: 征服王 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 156  Solved: 48[Submit][Status][Discuss] D ...

  3. bzoj2893(费用流)

    先缩点,然后拆点,其实是很经典的一种操作,把不好做的点拆成边,然后我一开始想的是网络流,答案当然是增广次数, 但可以发现跑网络流的话不同的跑法增广次数不一样,不太好找最小的.我们可以换一种神奇的思路, ...

  4. hdu-5988 Coding Contest(费用流)

    题目链接: Coding Contest Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Ot ...

  5. POJ2195 Going Home[费用流|二分图最大权匹配]

    Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 22088   Accepted: 11155 Desc ...

  6. BZOJ3130: [Sdoi2013]费用流[最大流 实数二分]

    3130: [Sdoi2013]费用流 Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 960  Solved: 5 ...

  7. 洛谷 1004 dp或最大费用流

    思路: dp方法: 设dp[i][j][k][l]为两条没有交叉的路径分别走到(i,j)和(k,l)处最大价值. 则转移方程为 dp[i][j][k][l]=max(dp[i-1][j][k-1][l ...

  8. Codeforces 730I [费用流]

    /* 不要低头,不要放弃,不要气馁,不要慌张 题意: 给两行n个数,要求从第一行选取a个数,第二行选取b个数使得这些数加起来和最大. 限制条件是第一行选取了某个数的条件下,第二行不能选取对应位置的数. ...

  9. zkw费用流+当前弧优化

    zkw费用流+当前弧优化 var o,v:..] of boolean; f,s,d,dis:..] of longint; next,p,c,w:..] of longint; i,j,k,l,y, ...

随机推荐

  1. Join 具体用法

    一.Join 语法概念 Join 按照功能可分为三大类: left join (左连接) 即:取左边表的全部数据,即使右边表没有对应的数据,也是会把左边表的数据取出来,并返回 right join(右 ...

  2. MyBatis开发Dao层的两种方式(原始Dao层开发)

    本文将介绍使用框架mybatis开发原始Dao层来对一个对数据库进行增删改查的案例. Mapper动态代理开发Dao层请阅读我的下一篇博客:MyBatis开发Dao层的两种方式(Mapper动态代理方 ...

  3. 解决盒子浮动时margin会显示两倍的美观问题

    当给几个大小一样有boder的盒子浮动时,会出现margin自动加起来的结果. 此时可以给每个盒子一个margin-left:-border的长来实现很好的效果,这样右边的盒子会把左边盒子的右边bor ...

  4. Windows Server 2008R2常见的500错误

    每次公司服务器装系统后再去部署服务,都会碰到这个问题,这里记录一下问题的解决方法 遇到“500 – 内部服务器错误. 您查找的资源存在问题,因而无法显示.”的问题. 解决办法: 1.解决方法:打开II ...

  5. POJ3159(KB4-K 差分约束)

    Candies Time Limit: 1500MS   Memory Limit: 131072K Total Submissions: 33283   Accepted: 9334 Descrip ...

  6. 【读书笔记】iOS-网络-运行循环

    运行循环是由类NSRunLoop表示的,有些线程可以让操作系统唤醒睡眠的线程以管理到来的事件,而运行循环则是这些线程的基本组件.运行循环是这样一种循环,可以在一个周期内调度任务并处理到来的事件.iOS ...

  7. TNS-12549问题分析及解决办法

    该服务器启动监听时候报错因为最后一句是Linux Error:No space left on device 因为是LINUX Error,所以可以到/var/log/messages里查看具体报错信 ...

  8. 【CLR Via C#】16 数组

    所有的数组都隐式的从System.Array抽象类派生,后者又派生自System.Object 数组是引用类型,所以会在托管堆上分配内存,数组对象占据的内存块包含数组的元素,一个类型对象指针.一个同步 ...

  9. SQLServer 学习笔记之超详细基础SQL语句 Part 3

    Sqlserver 学习笔记 by:授客 QQ:1033553122 -----------------------接Part 2------------------- 13. 使用compute对查 ...

  10. Flutter开发中的几个常用函数

    几个Flutter开发中的常用函数 /** 返回当前时间戳 */ static int currentTimeMillis() { return new DateTime.now().millisec ...