题目链接:
题意:
一张图有N个顶点,给出一些有向边,问该如何给这些边赋值才能 满足d(1)<d(2)<....d(x)>d(x+1)>...d(n) 的条件
且1为起点,d(x)表示1到x的最短距离. 赋值的范围在1~N
解题思路:
如果我们知道每个点的dis值和最短路径树的话,方案是很容易构造的
我们可以采取贪心做法,然后左边从1开始,右边从n开始,只要之前加入的点有边连向他们就加入
这样一个点加入的时间就是他的disdis值,最短路径树上的父亲也可以确定,于是输出时非树边长度为n,树边长度为两个端点dis之差
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 300050
using namespace std;
struct node{
int from,to,next;
}edge[maxn<<1];
int head[maxn],ss;
int fa[maxn];
int dis[maxn];
void addedge(int a,int b)
{
edge[ss]=(node){a,b,head[a]};
head[a]=ss++;
}
void init()
{
memset(fa,0,sizeof(fa));
memset(head,-1,sizeof(head));
ss=0;
fa[1]=-1;
dis[1]=0;
}
void expand(int u)
{
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(!fa[v])
fa[v]=u;
}
}
int main()
{
int T,n,m,a,b;
int s,l,r;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d",&a,&b);
addedge(a,b);
}
s=1;
l=1,r=n;
while(l<=r)
{
if(fa[l])
{
expand(l);
dis[l++]=s++;
}
if(fa[r])
{
expand(r);
dis[r--]=s++;
}
}
for(int i=0;i<ss;i++)
{
a=edge[i].from;
b=edge[i].to;
if(fa[b]!=a)
printf("%d\n",n);
else
printf("%d\n",dis[b]-dis[a]);
}
}
return 0;
}