题目链接:点击打开链接
题意:一张图有N个顶点,给出一些有向边,问该如何给这些边赋值才能满足d(1) < d(2) < ….d(x) > d(x+1) > …d(n) 的条件且1为起点,d(x)表示1到x的最短距离. 赋值的范围在1~N。
解题思路:左边从2开始,右边从n开始,每次选与之前标记过的点相连的未标记过得点,该点的d[i]为该点加入的时间。最后输出时,判断该点是否在最短路上,不在的话,输出n,在的话输出d[v] - d[u]。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <climits>
using namespace std;
#define eps 1e-8;
const int INF=0x3f3f3f3f;
const int maxn=300000+10;
const int maxm=600000+10;
int d[maxn];
int f[maxn];
int n,m;
struct Edge
{
int from,to;
Edge(int from,int to):from(from),to(to){}
};
vector<Edge> edges;
vector<int> G[maxn];
void init()
{
memset(f,0,sizeof(f));
fill(d,d+n+1,INF);
edges.clear();
for(int i=1;i<=n;i++)G[i].clear();
d[1]=0;
d[2]=1;
d[n]=1;
f[1]=-1;
}
void addEdge(int from,int to) //邻接表实现
{
edges.push_back(Edge(from,to));
int x=edges.size();
G[from].push_back(x-1);
}
void mark(int x)
{
for(int i=0;i<G[x].size();i++)
{
int v=edges[G[x][i]].to;
if(!f[v])f[v]=x;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
init();
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);
}
int l=1,r=n;
int dis=1;
while(l<=r)
{
if(f[l])
{
mark(l);
d[l]=dis++;
l++;
}
if(f[r])
{
mark(r);
d[r]=dis++;
r--;
}
}
for(int i=0;i<m;i++)
{
int u=edges[i].from;
int v=edges[i].to;
if(f[v]!=u)printf("%d\n",n);
else printf("%d\n",d[v]-d[u]);
}
}
return 0;
}