Pizza Delivery
Pizza Delivery
时间限制: 2 Sec 内存限制: 128 MB
题目描述
Alyssa orders a piece of pizza everyday from the same pizzeria. The pizza is delivered along the shortest route from the intersection with the pizzeria to the intersection with Alyssa’s house.
Altering the traffic regulation may change the shortest route. Please tell Alyssa how the social experiment will affect the pizza delivery route.
输入
n m
a1 b1 c1
.
.
.
am bm cm
The first line contains two integers, n, the number of intersections, and m, the number of street sections in New Tsukuba City (2 ≤ n ≤ 100 000, 1 ≤ m ≤ 100 000). The intersections are numbered 1 through n and the street sections are numbered 1 through m.
The following m lines contain the information about the street sections, each with three integers ai, bi, and ci (1 ≤ ai ≤ n, 1 ≤ bi ≤ n, ai ≠ bi, 1 ≤ ci ≤ 100 000). They mean that the street section numbered i connects two intersections with the one-way direction from ai to bi, which will be reversed on the i-th day. The street section has the length of ci. Note that there may be more than one street section connecting the same pair of intersections.
The pizzeria is on the intersection 1 and Alyssa’s house is on the intersection 2. It is guaranteed that at least one route exists from the pizzeria to Alyssa’s before the social experiment starts.
输出
• HAPPY if the shortest route on the i-th day will become shorter,
• SOSO if the length of the shortest route on the i-th day will not change, and
• SAD if the shortest route on the i-th day will be longer or if there will be no route from the pizzeria to Alyssa’s house.
Alyssa doesn’t mind whether the delivery bike can go back to the pizzeria or not.
样例输入
4 5
1 3 5
3 4 6
4 2 7
2 1 18
2 3 12
样例输出
SAD
SAD
SAD
SOSO
HAPPY
来源/分类
题意:有向图中,翻转某一条边,问最短路径如何变化(变长,变短,不变)。
分析:设 d(u,v)代表从u到v的最短路,s为起点,t为终点。对于任一边(from,to),若d(s,to)+d(from,t)+value(from,to)< d(s,t),则翻转该边最短路减小。再求出所有最短路径所在的图,该图是DAG,若某一条边是DAG上的桥,则翻转该边后最短路径增大,否则不变。
证明参考:https://icpc.iisf.or.jp/2017-tsukuba/wp-content/uploads/sites/4/2017/12/commentaries2.pdf
做法:求最短路径的话正反跑两遍最短路就好了,让我感觉比较难的地方是求所有最短路径的DAG以及DAG上的桥。
求所有最短路径组成的DAG:对于任一条边(from,to),若d(s,from)+d(to,t)+value(from,to)== d(s,t),则该边是DAG上的边。
求DAG上的桥:第一种方法是把DAG上的有向边全部转化为无向边,然后用tarjan算法求无向图的桥。第二种方法是先统计出S到T的方案数,则有结论:如果这条边是桥边,那么这条边两边的点x、y也是必经点,而且s到x的方案数*y到t的方案数=s到t的方案数,这个是充分必要的。
tarjan求桥:
#include<bits/stdc++.h>
#define N 200050
using namespace std; typedef struct
{
int from,to,value,ori;
} ss; ss edg1[N],edg2[N];
vector<int>edges1[N];
int now_edges1=;
vector<int>edges2[N];
int now_edges2=; int is_bridge[N]= {};
long long dis1[N],dis2[N]; void spfa1()
{
for(int i=; i<N; i++)dis1[i]=LLONG_MAX/;
int vis[N]= {};
queue<int>q;
q.push();
vis[]=;
dis1[]=; while(!q.empty())
{
int now=q.front();
q.pop();
vis[now]=; int Size=edges1[now].size();
for(int i=; i<Size; i++)
{
ss e=edg1[edges1[now][i]];
if(dis1[e.to]>dis1[now]+e.value)
{
dis1[e.to]=dis1[now]+e.value; if(!vis[e.to])
{
q.push(e.to);
vis[e.to]=;
}
}
}
}
} void spfa2()
{
for(int i=; i<N; i++)dis2[i]=LLONG_MAX/;
int vis[N]= {};
queue<int>q;
q.push();
vis[]=;
dis2[]=; while(!q.empty())
{
int now=q.front();
q.pop();
vis[now]=; int Size=edges2[now].size();
for(int i=; i<Size; i++)
{
ss e=edg2[edges2[now][i]];
if(dis2[e.to]>dis2[now]+e.value)
{
dis2[e.to]=dis2[now]+e.value; if(!vis[e.to])
{
q.push(e.to);
vis[e.to]=;
}
}
}
}
} int dfn[N]= {},low[N]= {},now_clo=; void tarjan(int x,int pre)
{
dfn[x]=low[x]=now_clo++;
int Size=edges2[x].size(); for(int i=; i<Size; i++)
{
ss e=edg2[edges2[x][i]]; if(e.to!=pre)
{
if(!dfn[e.to])
{
tarjan(e.to,x);
low[x]=min(low[x],low[e.to]); if(low[e.to]>dfn[x])
{
is_bridge[e.ori]=;
} }
else
{
low[x]=min(low[x],dfn[e.to]);
}
}
}
} int main()
{
int n,m;
scanf("%d %d",&n,&m); for(int i=; i<=m; i++)
{
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
edges1[u].push_back(now_edges1);
edg1[now_edges1++]=(ss){u,v,w,i};
edges2[v].push_back(now_edges2);
edg2[now_edges2++]=(ss){v,u,w,i};
} spfa1();
spfa2(); long long bestedge=dis1[]; for(int i=; i<N; i++)edges2[i].clear();
now_edges2=; for(int i=; i<=n; i++)
{
int Size=edges1[i].size();
for(int j=; j<Size; j++)
{
int u=i,v=edg1[edges1[i][j]].to,w=edg1[edges1[i][j]].value,ori=edg1[edges1[i][j]].ori; if(dis1[u]+dis2[v]+w==bestedge)
{
edges2[u].push_back(now_edges2);
edg2[now_edges2++]=(ss){u,v,,ori};
edges2[v].push_back(now_edges2);
edg2[now_edges2++]=(ss){v,u,,ori};
}
}
} tarjan(,-); int ans[N]= {};
for(int i=; i<=n; i++)
{
int Size=edges1[i].size();
for(int j=; j<Size; j++)
{
int u=i,v=edg1[edges1[i][j]].to,w=edg1[edges1[i][j]].value,ori=edg1[edges1[i][j]].ori; if(dis1[v]+dis2[u]+w<bestedge)ans[ori]=;
else if(is_bridge[ori])ans[ori]=-;
}
} for(int i=; i<=m; i++)
if(ans[i]==)printf("HAPPY\n");
else if(ans[i]==-)printf("SAD\n");
else
printf("SOSO\n");
return ; }
统计路径数求桥:
#include<bits/stdc++.h>
#define N 200050
using namespace std; typedef struct
{
int from,to,value,ori;
} ss; ss edg1[N],edg2[N];
vector<int>edges1[N];
int now_edges1=;
vector<int>edges2[N];
int now_edges2=; int is_in_dag[N]= {};
long long dis1[N],dis2[N]; void spfa1()
{
for(int i=; i<N; i++)dis1[i]=LLONG_MAX/;
int vis[N]= {};
queue<int>q;
q.push();
vis[]=;
dis1[]=; while(!q.empty())
{
int now=q.front();
q.pop();
vis[now]=; int Size=edges1[now].size();
for(int i=; i<Size; i++)
{
ss e=edg1[edges1[now][i]];
if(dis1[e.to]>dis1[now]+e.value)
{
dis1[e.to]=dis1[now]+e.value; if(!vis[e.to])
{
q.push(e.to);
vis[e.to]=;
}
}
}
}
} void spfa2()
{
for(int i=; i<N; i++)dis2[i]=LLONG_MAX/;
int vis[N]= {};
queue<int>q;
q.push();
vis[]=;
dis2[]=; while(!q.empty())
{
int now=q.front();
q.pop();
vis[now]=; int Size=edges2[now].size();
for(int i=; i<Size; i++)
{
ss e=edg2[edges2[now][i]];
if(dis2[e.to]>dis2[now]+e.value)
{
dis2[e.to]=dis2[now]+e.value; if(!vis[e.to])
{
q.push(e.to);
vis[e.to]=;
}
}
}
}
} ss edg3[N],edg4[N];
vector<int>edges3[N];
int now_edges3=;
vector<int>edges4[N];
int now_edges4=; long long num_ways_1[N]={},num_ways_2[N]={};
const long long mod=1e9+; long long dfs1(int x)
{
if(num_ways_1[x])return num_ways_1[x]; long long sum=;
int Size=edges3[x].size();
for(int i=;i<Size;i++)
{
int to=edg3[edges3[x][i]].to;
sum=(sum+dfs1(to))%mod;
} return num_ways_1[x]=sum; } long long dfs2(int x)
{
if(num_ways_2[x])return num_ways_2[x]; long long sum=;
int Size=edges4[x].size();
for(int i=;i<Size;i++)
{
int to=edg4[edges4[x][i]].to;
sum=(sum+dfs2(to))%mod;
} return num_ways_2[x]=sum;
} int main()
{ int n,m;
scanf("%d %d",&n,&m); for(int i=; i<=m; i++)
{
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
edges1[u].push_back(now_edges1);
edg1[now_edges1++]=(ss){u,v,w,i};
edges2[v].push_back(now_edges2);
edg2[now_edges2++]=(ss){v,u,w,i};
} spfa1();
spfa2(); long long bestedge=dis1[]; for(int i=; i<=n; i++)
{
int Size=edges1[i].size();
for(int j=; j<Size; j++)
{
int u=i,v=edg1[edges1[i][j]].to,w=edg1[edges1[i][j]].value,ori=edg1[edges1[i][j]].ori; if(dis1[u]+dis2[v]+w==bestedge)
{
is_in_dag[ori]=; edges3[u].push_back(now_edges3);
edg3[now_edges3++]=(ss){u,v,,ori};
edges4[v].push_back(now_edges4);
edg4[now_edges4++]=(ss){v,u,,ori};
}
}
} num_ways_1[]=;
num_ways_2[]=; int ans[N]={};
for(int i=;i<=n;i++)
{
int Size=edges1[i].size();
for(int j=;j<Size;j++)
{
int u=i,v=edg1[edges1[i][j]].to,w=edg1[edges1[i][j]].value,ori=edg1[edges1[i][j]].ori; if(!is_in_dag[ori]&&dis1[v]+dis2[u]+w<bestedge)ans[ori]=;
else
if(is_in_dag[ori]&&dfs1(v)*dfs2(u)%mod==dfs1())ans[ori]=-;
}
} for(int i=;i<=m;i++)
if(ans[i]==)printf("HAPPY\n");
else
if(ans[i]==-)printf("SAD\n");
else
printf("SOSO\n");
return ; }
Pizza Delivery的更多相关文章
- 【暑假】[深入动态规划]UVa 1628 Pizza Delivery
UVa 1628 Pizza Delivery 题目: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=51189 思路: ...
- uva1628 Pizza Delivery
fixing great wall 的变形dp(i,j,k,p)不考虑i-j的客人,还要送k个人,目前位置在p起点i和总数量k都要枚举dp(i,j,k,p)=max(dp(m,j,k-1,p)+val ...
- UVa1628 UVaLive5847 Pizza Delivery
填坑系列(p.302) 既然不知道后面还要卖多少个就加一维状态嘛.. lrj写的O(n)转移?其实转移可以O(1) 貌似按x排序有奇效? #include<cstdio> #include ...
- Aizu - 1383 Pizza Delivery (最短路图+DAG上的割边)
题意:给出一张有向图,每条边有长度,对于每条边,你要回答将该边的方向取反后,从起点到终点的最短距离是增加or减小or不变. 首先求出起点到所有点的最短距离和所有点到终点的最短距离(两次DIjkstra ...
- (好题)2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest F Pizza Delivery
题意:给n个点m条边的有向图.每次使一条边反向,问你1到2的最短路变短,变长,还是不变. 解法:遇到这种题容易想到正向求一遍最短路d1,反向再求一遍最短路d2.纪录原图上的最短路为ans,然后分开考虑 ...
- [GodLove]Wine93 Tarining Round #1
比赛链接: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=44664#overview 题目来源: 2011 Asia Regional ...
- CodeForces 151B Phone Numbers
Phone Numbers Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Sub ...
- Asia-Tsukuba 2017
A. Secret of Chocolate Poles DP,$f[i][j]$表示高度为$i$,顶层颜色为$j$的方案数. 时间复杂度$O(l)$. #include<cstdio> ...
- 2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest
2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest A Secret of Chocolate Poles 思路:暴力枚举黑巧克力的个数和厚黑巧克力的个 ...
随机推荐
- spring 中bean学习笔记
spring 中bean 一.bean的定义和应用 1. bean 形象上类似于getXX()和setXX()的一种. 2. 由于java是面向对象的,类的方法和属性在使用中需要实例化. 3. 规律: ...
- Servlet Context
Servlet Context Container Provider 负责提供ServletContext的实现. A ServletContext is rooted at a known path ...
- Google Colab免费GPU使用教程(一)
一.前言 现在你可以开发Deep Learning Applications在Google Colaboratory,它自带免费的Tesla K80 GPU.重点是免费.免费!(国内可能需要tz) 这 ...
- dfs染色法判定二分图
#include<iostream> #include<cstring> using namespace std; ][],color[],n; int dfs(int x,i ...
- c#写出乘法口诀
显然是显得无聊五分钟写的乘法口诀 static void Main(string[] args) { int dq; int[] array ...
- 判断NumLock键和CapsLock键是否被锁定
实现效果: 知识运用: AIP函数GetKeyState //针对已处理过的按键 在最近一次输入信息时 判断指定虚拟键的状态 intkey:预测试的虚拟键键码 实现代码: [DllImport(&qu ...
- python_112_断言
#断言 如果满足断言的执行程序,如果不满足则抛错误 assert type(1) is int print('断言正确的话,就继续执行') # assert type('a') is int #Ass ...
- c++ 中的函数调用中的参数传递
概述 初学 \(c++\),一直搞不懂其参数传递方式.故找到一篇不错的文章:刘志华的深入探讨C++语言中参数传递问题.亲自实践一遍,并作此记录,以加深印象. 主要内容 本文主要分为五个小部分, ...
- 测试框架 Mocha 实例教程(转载:来自阮一峰的一篇文章)
Mocha(发音"摩卡")诞生于2011年,是现在最流行的JavaScript测试框架之一,在浏览器和Node环境都可以使用. 所谓"测试框架",就是运行测试的 ...
- 【Qt】2.2 继续了解信号和槽
槽和普通成员函数一样,可以是虚函数.被重载,可以是公有.私有.保护的.它可以被其它C++成员函数调用. 槽连接了信号,当发射这个信号时,槽会被自动调用. 连接函数: bool QObject::con ...