这道题要求每个节点只能经过一次,也就是结点容量为1, 要拆点, 拆成两个点, 中间连一条弧容量为1, 费用为0.
因为拆成两个点, 所以要经过原图中的这个节点就要经过拆成的这两个点, 又因为这两个点的

边的容量为1, 所以只能经过一次, 就等价于原图中的点只能经过一次。

拆点的时候要注意细节:起点和终点不用拆, 因为有两条路径, 所以起点和终点必须经过两次。

因此一开始的时候只拆2到n-1这些点, 拆成i与n+i。起点是1, 终点是n, 源点是0, 汇点是2 * n + 1

然后后来加边的时候, 如果非源点和终点, 连接的时候是拆出来的点连原来的点, 如果是起点

和终点, 那么就是原来的点相连。最后再把源点和起点连一条弧, 容量为2, 表示有两条路径, 终点


与汇点也一样

最后求最小费用流就ok了。

#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std; typedef long long ll;
const int MAXN = 4123;
struct Edge
{
int from, to, cap, flow, cost;
Edge(int from, int to, int cap, int flow, int cost) : from(from), to(to), cap(cap), flow(flow), cost(cost) {};
};
vector<Edge> edges;
vector<int> g[MAXN];
int p[MAXN], a[MAXN], d[MAXN], vis[MAXN], n, m, s, t; void AddEdge(int from, int to, int cap, int cost)
{
edges.push_back(Edge(from, to, cap, 0, cost));
edges.push_back(Edge(to, from, 0, 0, -cost));
g[from].push_back(edges.size() - 2);
g[to].push_back(edges.size() - 1);
} bool spfa(int& flow, ll& cost)
{
REP(i, 0, t + 1) d[i] = (i == s ? 0 : 1e9);
memset(vis, 0, sizeof(vis));
vis[s] = 1; p[s] = 0; a[s] = 1e9; queue<int> q;
q.push(s);
while(!q.empty())
{
int u = q.front(); q.pop();
vis[u] = 0;
REP(i, 0, g[u].size())
{
Edge& e = edges[g[u][i]];
if(e.cap > e.flow && d[e.to] > d[u] + e.cost)
{
d[e.to] = d[u] + e.cost;
p[e.to] = g[u][i];
a[e.to] = min(a[u], e.cap - e.flow);
if(!vis[e.to]) { vis[e.to] = 1; q.push(e.to); }
}
}
} if(d[t] == 1e9) return false;
flow += a[t];
cost += (ll)d[t] * (ll)a[t];
for(int u = t; u != s; u = edges[p[u]].from)
{
edges[p[u]].flow += a[t];
edges[p[u] ^ 1].flow -= a[t];
}
return true;
} int mincost(ll& cost)
{
int flow = 0; cost = 0;
while(spfa(flow, cost));
return flow;
} int main()
{
while(~scanf("%d%d", &n, &m) && n)
{
REP(i, 0, 2 * n + 1) g[i].clear();
edges.clear();
s = 0, t = 2 * n + 1; for(int i = 2; i <= n - 1; i++) AddEdge(i, n + i, 1, 0);
while(m--)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
if(u != 1 && u != n) AddEdge(u + n, v, 1, w);
else AddEdge(u, v, 1, w);
} ll ans;
AddEdge(s, 1, 2, 0);
AddEdge(n, t, 2, 0);
mincost(ans);
printf("%lld\n", ans);
} return 0;
}

紫书 例题11-9 UVa 1658 (拆点+最小费用流)的更多相关文章

  1. UVa 1658 (拆点法 最小费用流) Admiral

    题意: 给出一个有向带权图,求从起点到终点的两条不相交路径使得权值和最小. 分析: 第一次听到“拆点法”这个名词. 把除起点和终点以外的点拆成两个点i和i',然后在这两点之间连一条容量为1,费用为0的 ...

  2. 紫书 例题 11-13 UVa 10735(混合图的欧拉回路)(最大流)

    这道题写了两个多小时-- 首先讲一下怎么建模 我们的目的是让所有点的出度等于入度 那么我们可以把点分为两部分, 一部分出度大于入度, 一部分入度大于出度 那么显然, 按照书里的思路,将边方向后,就相当 ...

  3. 紫书 例题8-3 UVa 1152(中途相遇法)

    这道题要逆向思维, 就是求出答案的一部分, 然后反过去去寻找答案存不存在. 其实很多其他题都用了这道题目的方法, 自己以前都没有发现, 这道题专门考这个方法.这个方法可以没有一直往下求, 可以省去很多 ...

  4. 紫书 例题8-12 UVa 12627 (找规律 + 递归)

    紫书上有很明显的笔误, 公式写错了.g(k, i)的那个公式应该加上c(k-1)而不是c(k).如果加上c(k-1)那就是这一次 所有的红气球的数目, 肯定大于最下面i行的红气球数 我用的是f的公式, ...

  5. 紫书 例题8-4 UVa 11134(问题分解 + 贪心)

     这道题目可以把问题分解, 因为x坐标和y坐标的答案之间没有联系, 所以可以单独求两个坐标的答案 我一开始想的是按照左区间从小到大, 相同的时候从右区间从小到大排序, 然后WA 去uDebug找了数据 ...

  6. 紫书 例题8-17 UVa 1609 (构造法)(详细注释)

    这道题用构造法, 就是自己依据题目想出一种可以得到解的方法, 没有什么规律可言, 只能根据题目本身来思考. 这道题的构造法比较复杂, 不知道刘汝佳是怎么想出来的, 我想的话肯定想不到. 具体思路紫书上 ...

  7. 紫书 例题 9-5 UVa 12563 ( 01背包变形)

    总的来说就是价值为1,时间因物品而变,同时注意要刚好取到的01背包 (1)时间方面.按照题意,每首歌的时间最多为t + w - 1,这里要注意. 同时记得最后要加入时间为678的一首歌曲 (2)这里因 ...

  8. 紫书 例题 10-26 UVa 11440(欧拉函数+数论)

    这里用到了一些数论知识 首先素因子都大于M等价与M! 互质 然后又因为当k与M!互质且k>M!时当且仅当k mod M! 与M!互质(欧几里得算法的原理) 又因为N>=M, 所以N!为M! ...

  9. 紫书 例题7-14 UVa 1602(搜索+STL+打表)

    这道题想了很久不知道怎么设置状态,怎么拓展,怎么判重, 最后看了这哥们的博客 终于明白了. https://blog.csdn.net/u014800748/article/details/47400 ...

随机推荐

  1. 进程线程之pid,tid

    Linux中,每个进程有一个pid,类型pid_t,由getpid()取得.Linux下的POSIX线程也有一个id,类型pthread_t,由pthread_self()取得,该id由线程维护,其i ...

  2. 在使用easyui datagrid在tab中遇到的问题

    当切换tab时,数据加载了,但是table的宽和高不能不能够初始化. 郁闷了好久解决了这个问题: 在页面加载时和切换tab时,获取当前tab的名字,进行内容的初始化 $('a[name="m ...

  3. 8、Situation-Dependent Combination of Long-Term and Session-Based Preferences in Group Recommendations: An Experimental Analysis ----组推荐中基于长期和会话偏好的情景依赖组合

    一.摘要: 背景:会话组推荐系统的一个主要挑战是如何适当地利用群组成员之间的交互引起用户偏好,这可能会偏离用户的长期偏好.长期偏好和群组诱导的偏好之间的相对重要性应该根据具体的群组设置而变化. 本文: ...

  4. .net基础总复习(3)

    第三天 2.单例模式 1)  将构造函数私有化 2)  提供一个静态方法,返回一个对象 3)  创建一个单例 3.XML 可扩展的标记语言 XML:存储数据 注意: XML严格区分大小写,并且成对出现 ...

  5. iOS开发——GPUImage源码解析

    一.基本概念 GPUImage:一个开源的.基于openGL的图片或视频的处理框架,其本身内置了多达120多种常见的滤镜效果,并且支持照相机和摄像机的实时滤镜,并且能够自定义图像滤镜.同时也很方便在原 ...

  6. C++操作符重载总结operator(小结 更新ing)

    操作符重载一个原则是:被操作的数据类型中 至少有一个是自定义的类型(使用class定义类),如果被操作的变量都是基本类型,那么就不能定义操作符重载. 1.如果重载了new,则必须重载delete,因为 ...

  7. Qt Designer设计 UI 文件并调用

    本文介绍的是Qt Designer设计 UI 文件并调用,在坛子里逛了一圈,关于UI方面的好像不怎多,本篇给大家分享一下. AD: 2013云计算架构师峰会超低价抢票中 Qt Designer设计 U ...

  8. ActiveMQ学习总结(4)——业界消息队列简介

    最近开发公司的短信平台,要用到消息队列,之前用的是亚马逊的SQS,考虑到后续业务发展,对消息推送的高并发要求,公司决定采用RabbitMQ来替换.借此机会开始熟悉各种MQ产品,下面先给大家简介下业界常 ...

  9. Mybatis动态代理实现函数调用

    如果我们要使用MyBatis进行数据库操作的话,大致要做两件事情: 1. 定义DAO接口 在DAO接口中定义需要进行的数据库操作. 2. 创建映射文件 当有了DAO接口后,还需要为该接口创建映射文件. ...

  10. Javascript 实现锚点(Anchor)间平滑跳转

    (function($){ $.fn.scroller = function(options){ var defaultVal = { duration: }; var obj = $.extend( ...