题目链接

题意:

DAG的最小路径覆盖,一条边可以被重复覆盖多次,但是一次只能沿着DAG的方向覆盖一条链,问最少覆盖次数。

思路:

看了半天没有思路,所以去搜索了题解,然后发现是有源汇上下界的最小流,这个东西依赖于有源汇上下界的可行流,然后又依赖于无源汇上下界可行流,所以就都去学了一下,写一个简单的总结与建模方法。

无源汇上下界可行流:

首先强行指定每条边的流为下界,然后会很大概率出现流量不平衡的现象,那么现在需要让流量平衡,就需要补流与分流。

强行指定之后,设流入每个点的流量为\(in_i\),流出每个点的流量为\(out_i\),那么就有3种情况:

  • \(in_i = out_i\),此时无需做任何事情;
  • \(in_i > out_i\),流入的流量比流出的流量多,那么需要从附加源点\(SS\)引入\(in_i - out_i\)的流,即加边\(adde(SS,i,in[i]-out[i])\);
  • \(in_i < out_i\),流出的流量比流入的流量多,那么需要从点分流\(out_i - in_i\)到附加汇点\(TT\),即加边\(adde(i,TT,out[i]-in[i])\).

此时,只是处理完了需要流量平衡的地方,现在还需要对边的流量的上界进行限制,由于已经强行指定了边的下界,所以每一条边的上界都是原来的上界减去下界,按照这个限制对图加边即可。

最后,求\(SS\)到\(TT\)的最大流,如果满流,则说明这个图有可行流,并且每一条边的流为附加流加上指定的下界。

有源汇上下界可行流:

转化为无源汇上下界可行流,只需要加边\(adde(T,S,inf)\),如此就可以保证源点和汇点也流量平衡(无源汇可行流的基础就是流量平衡)。

加边之后,按照无源汇可行流求解即可,并且\(T\)到\(S\)的反向边的流量就是原图的一个可行流。

有源汇上下界最大流:

转化为有源汇上下界可行流,在这个残量网络上求从\(S\)到\(T\)的最大流,加上之前求的可行流即是本图的最大流。

有源汇上下界最小流:

转化为可行流问题,但是稍微有不同。

首先不连边\(adde(T,S,inf)\),然后求\(SS\)到\(TT\)的最大流;

之后连边\(adde(T,S,inf)\),再次求\(SS\)到\(TT\)的最大流,这个最大流就是我们所求的最小流,原理不太懂,参考

题目思路:

从源点到每个点连边,下界为0,上界为inf,表示这个点可以放下任意数量的人;

从每个点到汇点连边,下界为0,上界为inf,表示任意数量的人在这个点停止;

题目中给出的边,下界为1,上界为inf,表示每条边至少被覆盖一次。

然后求有源汇上下界最小流即可。

然后是找路径,dfs找到return即可。

但是得从S开始找,不要从某一个点开始找。假设从S到1的流量为3,但是1流出的总流量为5,从1开始dfs,就会出现某个后面的点无法找到路径的情况

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 2e2 + 5; vector<int> g[N];
vector<vector<int> > anc;
vector<int> tp;
int mp[N][N];
int in[N],out[N];
int dis[N],cur[N];
int S,T,SS,TT;
int st,en; struct edge
{
int u,v,cap,org;
edge(int u,int v,int cap,int org):u(u),v(v),cap(cap),org(org){}
}; vector<edge> es;
vector<int> G[N]; void adde(int u,int v,int cap)
{
es.push_back(edge(u,v,cap,cap));
es.push_back(edge(v,u,0,0));
int sz = es.size();
G[u].push_back(sz-2);
G[v].push_back(sz-1);
} bool bfs()
{
memset(dis,inf,sizeof dis);
dis[st] = 0;
queue<int> q;
q.push(st);
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = 0;i < G[u].size();i++)
{
edge &e = es[G[u][i]];
int v = e.v;
if (dis[v] >= inf && e.cap > 0)
{
dis[v] = dis[u] + 1;
q.push(v);
}
}
}
return dis[en] < inf;
} int dfs(int u,int flow)
{
if (u == en) return flow;
for (int i = cur[u];i < G[u].size();i++)
{
cur[u] = i;
edge &e = es[G[u][i]];
int v = e.v;
if (dis[v] == dis[u] + 1 && e.cap > 0)
{
int tmp = dfs(v,min(flow,e.cap));
if (tmp)
{
e.cap -= tmp;
es[G[u][i]^1].cap += tmp;
return tmp;
}
}
}
return 0;
} int dinic()
{
int ans = 0;
while (bfs())
{
memset(cur,0,sizeof cur);
int tmp;
while (tmp = dfs(st,inf)) ans += tmp;
}
return ans;
} void fin(int u)
{
tp.push_back(u);
for (int i = 0;i < g[u].size();i++)
{
int v = g[u][i];
if (mp[u][v])
{
mp[u][v]--;
fin(v);
return;
}
}
} int main()
{
int n;
while (~scanf("%d",&n))
{
for (int i = 0;i < N;i++)
{
g[i].clear();
G[i].clear();
}
es.clear();
memset(in,0,sizeof in);
memset(out,0,sizeof out);
memset(mp,0,sizeof mp);
anc.clear();
for (int i = 1;i <= n;i++)
{
int m;
scanf("%d",&m);
for (int j = 0;j < m;j++)
{
int x;
scanf("%d",&x);
g[i].push_back(x);
mp[i][x]++;
}
}
for (int i = 1;i <= n;i++)
{
for (int j = 0;j < g[i].size();j++)
{
int x = g[i][j];
out[i]++;
in[x]++;
}
}
S = 0;T = n + 1;
SS = n + 2;TT = n + 3;
for (int i = 1;i <= n;i++)
{
for (int j = 0;j < g[i].size();j++)
{
int x = g[i][j];
adde(i,x,inf);
}
}
int sum = 0;
for (int i = 1;i <= n;i++)
{
adde(S,i,inf);
adde(i,T,inf);
}
//adde(T,S,inf);
int cnt = 0;
for (int i = 1;i <= n;i++)
{
if (in[i] > out[i])
{
cnt++;
adde(SS,i,in[i] - out[i]);
sum += in[i] - out[i];
}
else if (in[i] < out[i])
{
cnt++;
adde(i,TT,out[i] - in[i]);
}
}
//puts("GG");
st = SS;en = TT; dinic(); adde(T,S,inf);
//printf("%d %d\n",sum,ans);
//if (ans == sum) puts("Yes");
//else puts("No"); int ans = dinic();
printf("%d\n",ans);
//printf("%d\n",dec);
for (int i = 1;i <= n;i++)
{
for (int j = 0;j < G[i].size();j++)
{
edge e = es[G[i][j]];
if (e.v == S || e.v == T || e.org == 0 || e.v == SS || e.v == TT) continue;
mp[i][e.v] += e.org - e.cap;
}
}
for (int i = 0;i < G[S].size();i++)
{
edge e = es[G[S][i]];
int v = e.v;
if (v >= 1 && v <= n)
{
int c = e.org - e.cap;
while (c)
{
tp.clear();
fin(v);
anc.push_back(tp);
c--;
}
}
}
for (int i = 0;i < anc.size();i++)
{
tp = anc[i];
int sz = tp.size();
for (int j = 0;j < sz;j++)
{
printf("%d%c",tp[j],j == sz - 1 ? '\n' : ' ');
}
}
}
return 0;
}
/*
8
1 3
1 7
2 4 5
1 8
1 8
0
2 6 5
0
*/

uva 1440 & uvalive 4597的更多相关文章

  1. 【题解】Inspection UVa 1440 LA 4597 NEERC 2009

    题目传送门:https://vjudge.net/problem/UVA-1440 看上去很像DAG的最小路径覆盖QwQ? 反正我是写了一个上下界网络流,建模方法清晰易懂. 建立源$s$,向每个原图中 ...

  2. UVaLive 4597 Inspection (网络流,最小流)

    题意:给出一张有向图,每次你可以从图中的任意一点出发,经过若干条边后停止,然后问你最少走几次可以将图中的每条边都走过至少一次,并且要输出方案,这个转化为网络流的话,就相当于 求一个最小流,并且存在下界 ...

  3. UVa 12716 && UVaLive 6657 GCD XOR (数论)

    题意:给定一个 n ,让你求有多少对整数 (a, b) 1 <= b <= a 且 gcd(a, b) = a ^ b. 析:设 c = a ^ b 那么 c 就是 a 的约数,那么根据异 ...

  4. UVa 12712 && UVaLive 6653 Pattern Locker (排列组合)

    题意:给定 一个n * n 的宫格,就是图案解锁,然后问你在区间 [l, r] 内的所有的个数进行组合,有多少种. 析:本来以为是数位DP,后来仔细一想是排列组合,因为怎么组合都行,不用考虑实际要考虑 ...

  5. UVa 12709 && UVaLive 6650 Falling Ants (水题)

    题意:给定 n 个长方体的长,宽,高,让你求高最大的时候体积最大是多少. 析:排序,用高和体积排序就好. 代码如下: #pragma comment(linker, "/STACK:1024 ...

  6. UVA 12124 UVAlive 3971 Assemble(二分 + 贪心)

    先从中找出性能最好的那个数, 在用钱比較少的去组合,能组出来就表明答案在mid的右边,反之在左边, #include<string.h> #include<map> #incl ...

  7. UVa 1440:Inspection(带下界的最小流)***

    https://vjudge.net/problem/UVA-1440 题意:给出一个图,要求每条边都必须至少走一次,问最少需要一笔画多少次. 思路:看了好久才勉强看懂模板.良心推荐:学习地址. 看完 ...

  8. POJ 3133 Manhattan Wiring (插头DP,轮廓线,经典)

    题意:给一个n*m的矩阵,每个格子中有1个数,可能是0或2或3,出现2的格子数为2个,出现3的格子数为2个,要求将两个2相连,两个3相连,求不交叉的最短路(起终点只算0.5长,其他算1). 思路: 这 ...

  9. poj1639,uva1537,uvalive2099,scu1622,fzu1761 Picnic Planning (最小限制生成树)

    Picnic Planning Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 10742   Accepted: 3885 ...

随机推荐

  1. 20190603 - CentOS 7 提示 Failed to load SELinux policy. Freezing 导致卡住不启动的解决办法

    现象 最近 Windows 和两台 Mac 混用,将 Windows VirtualBox 中安装的 CentOS 7 拷贝到 Mac 上. 启动 CentOS 7 时,图形界面进度卡在最后,按 Es ...

  2. Tensorflow 用训练好的模型预测

    本节涉及点: 从命令行参数读取需要预测的数据 从文件中读取数据进行预测 从任意字符串中读取数据进行预测 一.从命令行参数读取需要预测的数据 训练神经网络是让神经网络具备可用性,真正使用神经网络时,需要 ...

  3. DRF序列化器的使用

    序列化器的使用 序列化器的使用分两个阶段: 在客户端请求时,使用序列化器可以完成对数据的反序列化. 在服务器响应时,使用序列化器可以完成对数据的序列化. 序列化的基本使用 使用的还是上一篇博文中使用的 ...

  4. jQuery 相关插件

    jQuery 是一个快速的,简洁的 javaScript 库,使用户能更方便地处理 HTML documents.events.实现动画效果,并且方便地为网站提供 AJAX 交互. jQuery 还有 ...

  5. Oracle-DQL 3- 单行函数

    单行函数: --使用函数对表中的数据进行运算和处理,针对每行数据返回一个结果,叫做单行函数--包括数字函数,字符函数,日期函数,转换函数,其他函数 1.数字函数 --round(m,n) 将数字m精确 ...

  6. windows登录密码忘记了怎么办?

    利用PE工具进行进行修改密码或者重置系统密码,正对于服务器也同样试用 目前U启动制作效果还不错,黑鲨一键装机,以及老毛桃我觉得还是算了,U深度也不错 经过这么久,小编也把该测试的测试了,,小编比较懒, ...

  7. 七牛云图床及MPIC工具使用

    考虑到图片更容易被人接受,但是大量图片又会延迟博客加载速度.因此,个人感觉可以把静态文件资源托管在云端,这样加载的话就不至于太慢. 注册七牛云 实名验证通过 创建文件存储 内容管理-上传图片 下载Mp ...

  8. 技能节-AI人脸识别

    我们收到技能节项目的通知是在两周之前,项目要求做个人脸评分系统. 两周时间写一个"人脸评分系统",好像时间比较紧了,还好我们完成了~这个项目是将摄像头捕获到的包含人脸的图像传输到百 ...

  9. IIS和apache并存windows服务器

    方法三: 将apache设为使用80端口,IIS使用其它端口,比如81,然后将apache作为IIS的代理.速度有影响.在httpd.conf里面,取消下面四行的注释:LoadModule proxy ...

  10. 一次简单的springboot+dubbo+flume+kafka+storm+redis系统

    最近无事学习一下,用springboot+dubbo+flume+kafka+storm+redis做了一个简单的scenic系统 scenicweb:展现层,springboot+dubbo sce ...