SGU185 - Two Shortest
原题地址:http://acm.sgu.ru/problem.php?contest=0&problem=185
题目大意:给出一个无向图,求出从 1 到 n 的两条没有相同边的最短路径(允许有重复点),要求输出具体路径,不存在则输出"No solution"。保证两点之间没有重边。
数据范围和限制:点数 2 <= N <= 400, 边长小于等于10000。时间限制 0.25s 内存限制 4M
题目分析:
这题应该算是经典题目了,半年之前第一遍写就没过,昨天复习图论时下定决心开始搞定这道题,结果无限WA,刚刚总算把它调对了。话说SGU我还没做过几道题呢(惭愧)……
题目首先要求最短路,而且两条路必须都是最短路,而不能是一条最短的和一条次短的。那我们不妨先求出从 1 出发的单源最短路,然后考察最短路中的最优子结构性质:即若从 1 到 i 的最短路上经过了点 j ,则必须要满足 dist[j] + map[j][i] == dist[i], 否则我们总能找到一条更短的路径。这样我们不妨直接把不满足以上性质的边全部删除就好了。
下一个要求是不能有重复边。我们可以以 1 为源点, n 为汇点,剩下所有边的容量设为 1,做一遍最大流,如果最大流大于等于 2则有可行解,写一个DFS输出流的路径就行了,否则说明无重叠最短路不存在,输出无解信息
//date 20140115
#include <cstdio>
#include <cstring> const int maxn = ;
const int maxm = ;
const int INF = 0x7F7F7F7F; inline int getint()
{
int ans(); char w = getchar();
while('' > w || '' < w)w = getchar();
while('' <= w && w <= '')
{
ans = ans * + w - '';
w = getchar();
}
return ans;
} inline int min(int a, int b){return a < b ? a : b;} int n, m;
int map[maxn][maxn]; struct edge
{
int u, v, c, next;
}E[maxm];
int a[maxn];
int nedge; inline void add(int u, int v, int c)
{
E[++nedge].u = u;
E[nedge].v = v;
E[nedge].c = c;
E[nedge].next = a[u];
a[u] = nedge;
} int dis[maxn];
inline void init()
{
static int q[maxn];
static int inQ[maxn];
memset(dis, 0x7F, sizeof dis);
memset(inQ, , sizeof inQ);
dis[] = ;
int l = , r = ; q[] = ; inQ[] = ;
while(l < r)
{
int x = q[(++l) % maxn];
for(int i = ; i <= n; ++i)
if(map[x][i] > && map[x][i] + dis[x] < dis[i])
{
dis[i] = map[x][i] + dis[x];
if(!inQ[i]){q[(++r) % maxn] = i; inQ[i] = ;}
}
inQ[x] = ;
} for(int i = ; i <= n; ++i)
for(int j = ; j <= n; ++j)
if((map[i][j] > ) && (dis[i] + map[i][j] > dis[j]))map[i][j] = ; nedge = ;
for(int i = ; i <= n; ++i)
for(int j = ; j <= n; ++j)
if(map[i][j] > )
{
add(i, j, );
add(j, i, );
}
} int now[maxn];
int lab[maxn]; inline int label()
{
static int q[maxn];
int l = , r = ;
memset(lab, 0xFF, sizeof lab);
q[] = ; lab[] = ;
while(l < r)
{
int x = q[++l];
for(int i = a[x]; i; i = E[i].next)
if(E[i].c > && lab[E[i].v] == -)
{
lab[E[i].v] = lab[x] + ;
q[++r] = E[i].v;
// now[x] = i;
}
}
return (lab[n] != -);
} inline int Dinic(int v, int f)
{
if(v == n)return f;
int w, res = ;
for(int i = now[v]; i; i = now[v] = E[i].next)
if((E[i].c > ) && (f > ) && (lab[v] + == lab[E[i].v]) && (w = Dinic(E[i].v, min(f, E[i].c))))
{
E[i].c -= w;
E[i ^ ].c += w;
f -= w;
res += w;
}
return res;
} inline int max_flow()
{
int ans = ;
for(int i = ; i <= n; ++i)now[i] = a[i];
while(label()){ans += Dinic(, INF);for(int i = ; i <= n; ++i)now[i] = a[i];}
return ans;
} void dfs(int v)
{
if(v == n)printf("%d\n", v);
for(int i = a[v]; i; i = E[i].next)if(E[i].c == && map[v][E[i].v] > && dis[v] + map[v][E[i].v] == dis[E[i].v])
{
printf("%d ", v); dfs(E[i].v); map[v][E[i].v] = ; return;
}
}
inline void output()
{
dfs(), dfs();
}
int main()
{
freopen("sgu185.in", "r", stdin);
freopen("sgu185.out", "w", stdout); n = getint(); m = getint();
memset(map, , sizeof map);
memset(a, , sizeof a);
memset(E, , sizeof E);
for(int i = ; i <= m; ++i)
{
int x, y, z;
x = getint(); y = getint(); z = getint();
map[x][y] = map[y][x] = z;
}
init();
int ans = max_flow();
if(ans < )printf("No solution\n");
else output();
return ;
}
代码说明:求最短路的时候我用的SPFA,使用邻接矩阵存储,删边之后重新建图使用邻接表,用Dinic求最大流最后DFS递归输出答案就行
一些心得和收获:昨天第一遍写的时候用了两个邻接表,但是SPFA忘记开滚动队列了,由于机房关门了回家之后也没细查。今早到学校之后重写了一遍Dijkstra版本的,但是Dijkstra好像写错了无限WA……之后该做SPFA(但还是邻接矩阵)终于查出没有滚动队列的问题,之后开始TLE on test33,才发现Dinic的当前弧优化没写好,后来改对了总算AC了,我也总算有了自己比较熟练的最大流模板了。今天一上来邻接表的范围算错了,算成了400 * 400 * 2(网络流反向边),结果被SGU内存限制卡的死死的,后来证明出最短路删边之后图就变成单向的了没必要 * 2。继续加油!
SGU185 - Two Shortest的更多相关文章
- SGU185 Two shortest(最小费用最大流/最大流)
题目求一张图两条边不重复的最短路. 一开始我用费用流做. 源点到1连容量2费用0的边:所有边,连u到v和v到u容量1费用cost的边. 总共最多会增广两次,比较两次求得的费用,然后输出路径. 然而死M ...
- [LeetCode] Encode String with Shortest Length 最短长度编码字符串
Given a non-empty string, encode the string such that its encoded length is the shortest. The encodi ...
- [LeetCode] Shortest Distance from All Buildings 建筑物的最短距离
You want to build a house on an empty land which reaches all buildings in the shortest amount of dis ...
- [LeetCode] Shortest Word Distance III 最短单词距离之三
This is a follow up of Shortest Word Distance. The only difference is now word1 could be the same as ...
- [LeetCode] Shortest Word Distance II 最短单词距离之二
This is a follow up of Shortest Word Distance. The only difference is now you are given the list of ...
- [LeetCode] Shortest Word Distance 最短单词距离
Given a list of words and two words word1 and word2, return the shortest distance between these two ...
- [LeetCode] Shortest Palindrome 最短回文串
Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. ...
- Leetcode: Encode String with Shortest Length && G面经
Given a non-empty string, encode the string such that its encoded length is the shortest. The encodi ...
- LeetCode 214 Shortest Palindrome
214-Shortest Palindrome Given a string S, you are allowed to convert it to a palindrome by adding ch ...
随机推荐
- [译]Java Thread join示例与详解
Java Thread join示例与详解 Java Thread join方法用来暂停当前线程直到join操作上的线程结束.java中有三个重载的join方法: public final void ...
- PhpExcel数组输出到Excel浏览器下载
经常是mysql查出二维数组,并且数组的带key也是有意义的,考虑到经常用,就打算弄个函数出来,方便以后用! 相对是规范的数组哈,具体可看下$data数组: 生成的excel第一行是对应的key: 直 ...
- php学习日志(2)-php变量
变量是用于存储数据的容器,与代数相似,可以给变量赋予某个确定的值(例如:$x=3)或者是赋予其它的变量(例如:$x=$y+$z).变量的定义主要有以下规则: 变量以$开始,后面跟着变量的名称: 变量名 ...
- PHPExcel导出excel文件
今天园子刚开,先来个货顶下,后续园丁qing我会再慢慢种园子的,希望大家多来园子逛逛. PHPExcel导出excel文件,先说下重要的参数要记住的东西 impUser() 导入方法 exportEx ...
- 学习W3SCHOOL 表单验证
//表单学习笔记 //建立一张表单的验证 <!DOCTYPE html> <html> <head> <meta http-equiv="Conte ...
- 实现在DevExpress.XtraGrid.GridControl的列头绘制复选框以实现全选的功能
首先新建一个Win Form测试项目,拖一个GridControl控件到窗体上. public partial class Form1 : Form { public Form1() { Initia ...
- DB天气app冲刺第十一天
今天是第十一天了.今天遇到了一个很麻烦的问题 就是程序好好的然后调试运行之后能够安装成功 但总是运行不了 一直闪退.最主要的问题是代码还没有问题,这是最让人揪心的一个问题了.因为有bug的话还可以改, ...
- Object调用静态方法
谁说空指针不能调用方法 public class Foo { public static void bar() { System.out.println("bar"); } pub ...
- Delphi XE5 如何设计并使用FireMonkeyStyle(转)
如何设计并使用FireMonkeyStyle FireMonkey使用Style来控制控件的显示方式. 每个控件都有一个StyleLookup属性,FireMonkey就是通过控件的这个属性来在当前窗 ...
- Netty4.x中文教程系列(二) – 白话概念
"Hello World"的代码固然简单,不过其中的几个重要概念(类)和 Netty的工作原理还是需要简单明确一下,至少知道其是负责什.方便自己以后更灵活的使用和扩展. 声明, ...