题解 CF241E Flights
题目大意
给出一个 \(n\) 个点 \(m\) 条边的 \(\texttt{DAG}\) ,给每条边设定边权为 \(1\) 或者 \(2\) ,使得 \(1\to n\) 的每条路径长度都相同。
\(n\le 10^3,m\le 5\times 10^3\)
思路
老实说,真的对得起 \(2600\) 的评分(以我现在的角度来看),正解应该算比较难想的吧。。。
首先肯定需要把没有用的路径删掉,就是不能从 \(1\to n\) 的路径。
首先我们会发现一个比较显然的结论:\(1\to i\) 的任意路径都应该相同。这个结论应该都能想到,但是应该怎么用呢?如果我们设 \(\text{dis}(i)\) 表示 \(1\to i\) 的最短路径长度,那么如果存在边 \(u\to v\),则有:
\[\text{dis}(u)+1\le \text{dis}(v)\le \text{dis}(u)+2
\]
然后我们发现这个东西我们可以用差分约束解决。时间复杂度则为 \(\texttt{SPFA}\) 的时间复杂度。
\(\texttt{Code}\)
#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define Int register int
#define MAXM 5005
#define MAXN 1005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int n,m;
PII Edge[MAXM];
int toop = 1,to[MAXM << 1],nxt[MAXM << 1],wei[MAXM << 1],tim[MAXN],vis[MAXN],dis[MAXN],head[MAXN];
void Add_Edge (int u,int v,int w){
// cout << u << " -> " << v << ": " << w << endl;
to[++ toop] = v,wei[toop] = w,nxt[toop] = head[u],head[u] = toop;
}
void Spfa (){
queue <int> q;
while (!q.empty()) q.pop ();
memset (vis,0,sizeof (vis));
memset (dis,0x3f,sizeof (dis));
q.push (1),vis[1] = 1,dis[1] = 0;
while (!q.empty()){
int u = q.front();q.pop ();vis[u] = 0,tim[u] ++;
if (tim[u] > n){
puts ("No");
exit (0);
}
for (Int i = head[u];i;i = nxt[i]){
int v = to[i],w = wei[i];
if (dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
if (!vis[v]) vis[v] = 1,q.push (v);
}
}
}
}
vector <int> G[2][MAXN];
int ans[MAXN],vis1[MAXN];
void dfs (int u,int ty){vis1[u] |= 1 << ty;for (int v : G[ty][u]) if (!(vis1[v] & (1 << ty)))dfs (v,ty);}
signed main(){
read (n,m);
for (Int i = 1,u,v;i <= m;++ i) read (u,v),Edge[i] = make_pair (u,v),G[0][u].push_back (v),G[1][v].push_back (u);
dfs (1,0),dfs (n,1);for (Int i = 1,u,v;i <= m;++ i){
u = Edge[i].first,v = Edge[i].second;
if (vis1[u] == 3 && vis1[v] == 3) Add_Edge (u,v,2),Add_Edge (v,u,-1);
}
Spfa ();
puts ("Yes");
for (Int i = 1;i <= m;++ i){
int u = Edge[i].first,v = Edge[i].second;
if (vis1[u] == 3 && vis1[v] == 3) write (dis[v] - dis[u]),putchar ('\n');
else puts ("1");
}
return 0;
}