Codeforces Round #372 (Div. 1) B. Complete The Graph 解题报告

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; 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值