Problem 1. Tree
Input file: tree.in
Output file: tree.out
Time limit: 1 second
给出 N 个点的树和 K,问能否把树划分成 N /K 个连通块,且每个连通块的点数都是 K。
Input
第 1 行,1 个整数 T ,表示数据组数。接下来 T 组数据,对于每组数据:
第 1 行,2 个整数 N, K。
接下来 (N − 1) 行,每行 2 个整数 Ai , Bi ,表示边 (Ai , Bi )。点用 1, 2, . . . , N 编号。
Output
对于每组数据,输出 YES或 NO。
题解:这个题很水,只是当时没想到而已!~~~
实际上我们把整棵树划分出来仅需要暴搜就好了~~~2333
我们从叶子节点向上回溯,叶子节点是1,其父亲的值就是各子节点的和,以此类推,回溯上去,一旦超过k显然就是无解了~等于k的话我们就归零重新计数。
代码:by nevermore
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 #define MAXN 100100 6 struct Link 7 { 8 int to, next; 9 }l[MAXN * 2]; 10 int first[MAXN]; 11 int add = 0; 12 void add_edge(int u, int v) 13 { 14 l[add].to = v; 15 l[add].next = first[u]; 16 first[u] = add ++; 17 } 18 int T, n, k; 19 int num[MAXN]; 20 int temp = 0; 21 bool use[MAXN]; 22 bool dfs(int x) 23 { 24 use[x] = 1; 25 for (int i = first[x]; ~ i; i = l[i].next) 26 { 27 if (!use[l[i].to]) 28 { 29 if (dfs(l[i].to)) 30 num[x] += num[l[i].to]; 31 else return false; 32 } 33 } 34 if (num[x] == k) num[x] -= k; 35 else if (num[x] > k) return false; 36 return true; 37 } 38 int main() 39 { 40 freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); 41 scanf("%d", &T); 42 while (T --) 43 { 44 memset(use, 0, sizeof(use)); 45 add = 0; 46 scanf("%d%d", &n, &k); 47 int u, v; 48 memset(first, -1, sizeof(first)); 49 for (int i = 1; i < n; i ++) 50 { 51 scanf("%d%d", &u, &v); 52 add_edge(u, v); 53 add_edge(v, u); 54 } 55 for (int i = 1; i <= n; i ++) num[i] = 1; 56 if (dfs(1) && n % k == 0) printf("YES\n"); 57 else printf("NO\n"); 58 for (int i = 0; i < add; i ++) 59 l[i].to = l[i].next = 0; 60 } 61 return 0; 62 }
Problem 2. Graph
给出 N 个点,M 条边的有向图,对于每个点 v,求 A(v) 表示从点 v 出发,能到达的编号最大的点。
Input
第 1 行,2 个整数 N, M 。
接下来 M 行,每行 2 个整数 Ui, Vi ,表示边 ?Ui, Vi?。点用 1, 2, . . . , N 编号。
Output
N 个整数 A(1), A(2), . . . , A(N )。
Note
• 对于 60% 的数据,1 ≤ N, K ≤ 10^3;
• 对于 100% 的数据,1 ≤ N, M ≤ 10^5。
正解:反向建图,从编号大的点往回跑bfs,更新每个点所能连到的最大编号。
代码:还是nevermore的,谁让他写好了呢?2333我不是代码的生成者,我只做代码的搬运工
1 #include <queue> 2 3 #include <cstdio> 4 5 #include <cstring> 6 7 #include <algorithm> 8 9 using namespace std; 10 11 12 13 14 #define MAXN 100100 15 16 17 18 19 struct Link 20 21 { 22 23 int to, next; 24 25 }l[MAXN]; 26 27 int first[MAXN]; 28 29 30 31 32 int add = 0; 33 34 void add_edge(int u, int v) 35 36 { 37 38 l[add].to = v; 39 40 l[add].next = first[u]; 41 42 first[u] = add ++; 43 44 } 45 46 47 48 49 int n, m; 50 51 int ans[MAXN]; 52 53 54 55 56 queue <int> q; 57 58 bool use[MAXN]; 59 60 61 62 63 void bfs(int s) 64 65 { 66 67 q.push(s); 68 69 use[s] = 1; 70 71 while (!q.empty()) 72 73 { 74 75 int x = q.front(); 76 77 q.pop(); 78 79 for (int i = first[x]; ~ i; i = l[i].next) 80 81 if (!use[l[i].to]) 82 83 { 84 85 ans[l[i].to] = max(ans[l[i].to], ans[x]); 86 87 use[l[i].to] = 1; 88 89 q.push(l[i].to); 90 91 } 92 93 } 94 95 } 96 97 98 99 100 int main() 101 102 { 103 104 freopen("graph.in", "r", stdin); 105 106 freopen("graph.out", "w", stdout); 107 108 scanf("%d%d", &n, &m); 109 110 int u, v; 111 112 memset(first, -1, sizeof(first)); 113 114 for (int i = 1; i <= m; i ++) 115 116 { 117 118 scanf("%d%d", &u, &v); 119 120 add_edge(v, u); 121 122 } 123 124 for (int i = 1; i <= n; i ++) ans[i] = i; 125 126 for (int i = n; i >= 1; i --) 127 128 if (ans[i] == i) 129 130 bfs(i); 131 132 for (int i = 1; i <= n; i ++) 133 134 printf("%d ", ans[i]); 135 136 return 0; 137 }
in fact 我自己的思路和这个一点都不一样,我自己的思想是借鉴的最短路算法,我们每次只需要计原来的总边权为路径上最大的编号,三角不等式更新的时候只需要取max记好了。
唉(此处是二声)~这些好像我都写过。。。。。2333具体代码参见之前的随笔“最大路”,改改,那里是最大的边的权值,改成标号就好了~~更简单了不是么?
第三题必有蹊跷。。。。