Codeforces Round #372 (Div. 1) B. Complete The Graph 解题报告
题目:B. Complete The Graph
ZS the Coder has drawn an undirected graph of n vertices numbered from 0 to n - 1 and m edges between them. Each edge of the graph is weighted, each weight is a positive integer.
The next day, ZS the Coder realized that some of the weights were erased! So he wants to reassign positive integer weight to each of the edges which weights were erased, so that the length of the shortest path between vertices s and t in the resulting graph is exactly L. Can you help him?
题目大意
给定一个无向图,其中有一些边权值未给定。问是否能给出这些边的权值,使得从s点到t点的最短路权值为l?若能,输出YES并给出所有边的权值;若不能,输出NO。
题解
很明显是最短路的问题,本来如果时间限制只有1s的话还需要对dij最短路算法的使用留下心,但本题给了4s的时限就完全不需要担心这些问题了。
主要思路就是
1. 先排除未给定的边做一次dij
2. 如果此时的st最短路权值小于L,输出NO
3. 如果此时的st最短路权值等于L,输出YES,并把其他所有未给定的边的权值赋为L+1,输出。(这里是一个坑点,要是这种情况特判错了就会一直卡在test5,不要问我为什么会知道)
4. 接下来就一条一条的修改未给定权值的边,每修改一次做一次dij(反正时间多),看此时的d[t]是否小 于L,如果小于,将这条边的权值重赋为L-d[t]+1,其他赋为L+1,输出。
5. 注意如果当前的边衔接的点都不于S点联通的话,不能直接扔,用队列装着重新放在最后即可,记得做循环的判重,避免死循环。
6. 如果所有的边都已给定但还是不能满足题意,输出NO。
代码如下:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
const int maxn=10010;
const long long inf=9223372036854775000;
struct node
{
int d,u;
operator < (const node& its) const
{
return d>its.d;
}
};
struct edge
{
int from,to,dist;
};
vector<int> g[maxn];
queue<int> unk;
vector<edge> edges;
int n,m,s,t;
int p[maxn*3];
bool done[maxn];
long long d[maxn];
long long l;
void dij(int x,int s)
{
priority_queue<node> q;
memset(done,false,sizeof(done));
for(int i=0;i<n;i++) d[i]=inf;
d[s]=0;
q.push((node){x,s});
while(!q.empty())
{
node x=q.top(); q.pop();
int u=x.u;
if(done[u]) continue;
if(d[u]>=inf-10) continue;
done[u]=true;
for(int i=0;i<g[u].size();i++)
{
edge& e=edges[g[u][i]];
if(e.dist!=0&&d[e.to]>d[u]+e.dist)
{
d[e.to]=d[u]+e.dist;
q.push((node){d[e.to],e.to});
}
}
}
}
int main()
{
scanf("%d%d%lld%d%d",&n,&m,&l,&s,&t);
memset(p,-1,sizeof(p));
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
edges.push_back((edge){a,b,c});
g[a].push_back(edges.size()-1);
if(c==0) unk.push(edges.size()-1);
edges.push_back((edge){b,a,c});
g[b].push_back(edges.size()-1);
}
dij(0,s);
if(d[t]<l)
{
printf("NO\n");
return 0;
}
else if(d[t]==l)
{
printf("YES\n");
for(int j=0;j<edges.size();j=j+2)
{
if(edges[j].dist==0) edges[j].dist=l+1;
printf("%d %d %d\n",edges[j].from,edges[j].to,edges[j].dist);
}
return 0;
}
while(!unk.empty())
{
int u=unk.front();
if(p[u]==unk.size()) break;
unk.pop();
int a=edges[u].from,b=edges[u].to;
if(d[a]>d[b]) swap(a,b);
if(d[a]>=inf-10)
{
unk.push(u);
p[u]=unk.size();
continue;
}
if(d[a]+1==d[b]) continue;
edges[u].dist=1;
edges[u^1].dist=1;
dij(0,s);
if(d[t]<=l)
{
edges[u].dist=l-d[t]+1;
printf("YES\n");
for(int j=0;j<edges.size();j=j+2)
{
if(edges[j].dist==0) edges[j].dist=l+1;
printf("%d %d %d\n",edges[j].from,edges[j].to,edges[j].dist);
}
break;
}
}
if(d[t]>l) printf("NO\n");
return 0;
}