题目链接:
题目描述:
给出一个有向图,有n个点,m条边。假设从1到x点的最短路的值用d(x),要求给每条边赋一个[1,n]边权值后,存在一个y属于[1,n]使得:d(1)<d(2)<d(3)...d(y-1)<d(y)>d(y+1)...d(n-1)>d(n),输出任意一种赋值方案。
解题思路:
因为分配好边权以后要满足这个式子:d(1)<d(2)<d(3)...d(y-1)<d(y)>d(y+1)...d(n-1)>d(n)。又因为在用prim求最小生成树的时候,向生成树上加点的顺序就满足:最先加入的点到树根的距离最短。然后我们就根据这个性质每次向生成树上加点就好了。每次加点要么加编号最小的,要么加编号最大的,并且记录加入时间,最后在生成树上的边权值为两端点加入时间之差,不在生成树上的边权值记为n即可。
比赛的时候感觉这个题目炒鸡高大上,想到套用各种算法,看了题解感觉自己蠢哭了好嘛?现在写题解呢,我竟然不知道要把这个题目分类到哪里合适了。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 100005; 9 struct node 10 { 11 int to, next, id; 12 } edge[maxn]; 13 14 struct Node 15 { 16 int l, r; 17 } p[maxn]; 18 int tot, head[maxn], dis[maxn]; 19 bool vis[maxn], ans[maxn]; 20 21 void init () 22 { 23 tot = 0; 24 memset (head, -1, sizeof(head)); 25 memset (ans, false, sizeof(ans)); 26 memset (dis, 0, sizeof(dis)); 27 memset (vis, false, sizeof(vis)); 28 } 29 30 void Add (int from, int to, int id) 31 { 32 edge[tot].to = to; 33 edge[tot].id = id; 34 edge[tot].next = head[from]; 35 head[from] = tot++; 36 } 37 38 void solve (int u, int time) 39 { 40 dis[u] = time; 41 for (int i=head[u]; i!=-1; i=edge[i].next) 42 { 43 int v = edge[i].to; 44 if (vis[v]) 45 continue; 46 vis[v] = true; 47 ans[edge[i].id] = true; 48 } 49 } 50 51 int main () 52 { 53 int t, n, m; 54 scanf ("%d", &t); 55 while (t --) 56 { 57 init (); 58 scanf ("%d %d", &n, &m); 59 60 for (int i=1; i<=m; i++) 61 { 62 scanf ("%d %d", &p[i].l, &p[i].r); 63 Add (p[i].l, p[i].r, i); 64 } 65 66 int s = 1, e = n, x = 0; 67 vis[s] = true; 68 69 while (s <= e) 70 { 71 if (vis[s]) 72 solve (s++, x++); 73 if (vis[e]) 74 solve (e--, x++); 75 } 76 77 for (int i=1; i<=m; i++) 78 if (ans[i]) 79 printf ("%d ", abs(dis[p[i].l] - dis[p[i].r])); 80 else 81 printf ("%d ", n); 82 83 } 84 return 0; 85 }