描述(A 输入文件 : A.input 输出文件 : A.output)
一个城市的构成是一颗n 个节点的树(2 ≤ n ≤ 200), 现在需要在树中找出两条不相交的路
径(即两条路径不能有重边也不能有重点),使得路径的长度的乘积最大。
输入描述
第一行一个数n 表示这个城市一共有 n 个节点。
接下来 n-1 行,每行两个数ai 和bi (1 ≤ ai,bi ≤ n ),分别表示从ai 到bi,有一条边,每条边
的长度为1。
输出描述
输出一行一个数表示两条路径长度最大的乘积。
样例数据
样例输入1:
7
1 2
1 3
1 4
1 5
1 6
1 7
样例输出1:
0
样例输入2:
6
1 2
2 3
2 4
5 4
6 4
样例输出2:
4
第一题没多大技术含量,枚举每一条边,把这棵树分成两棵子树,再在这两棵子树上求最大的路径,这里用两种
方法,第一种是树规,第二种是两次dfs,第一种这里就不讲了,就说第二种,首先从一个点开始深搜,找到一个离当
前点最远的一个点,再从这个点开始,找到一个离这个点最远的点,这两个点的距离是最远的。
然后两部分都执行以下这个,找出这个距离,相乘,不断更新结果就行了
Code
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<cctype> 6 #include<vector> 7 using namespace std; 8 typedef bool boolean; 9 template<typename T> 10 inline void readInteger(T& u){ 11 char x; 12 while(!isdigit((x = getchar()))); 13 for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0'); 14 ungetc(x, stdin); 15 } 16 typedef class Edge{ 17 public: 18 int end; 19 int next; 20 Edge(const int end = 0, const int next = 0):end(end),next(next){} 21 }Edge; 22 int ce; 23 int *h; 24 Edge* edge; 25 inline void addEdge(int from, int end){ 26 edge[++ce] = Edge(end, h[from]); 27 h[from] = ce; 28 } 29 int n; 30 int maxd; 31 int noded; 32 void dsearch(int node, int split, int depth, int last){ 33 for(int i = h[node]; i != 0; i = edge[i].next){ 34 if(i == split || i == split + 1 || edge[i].end == last) continue; 35 dsearch(edge[i].end, split, depth + 1, node); 36 } 37 if(maxd <= depth){ 38 maxd = depth; 39 noded = node; 40 } 41 } 42 int farSearch(int node, int split){ 43 dsearch(node, split, 0, 0); 44 int buf = noded; 45 maxd = 0; 46 dsearch(buf, split, 0, 0); 47 return maxd; 48 } 49 inline void init(){ 50 readInteger(n); 51 edge = new Edge[(const int)(2 * n + 1)]; 52 h = new int[(const int)(n + 1)]; 53 memset(h, 0, sizeof(int) * (n + 1)); 54 for(int i = 1, a, b; i < n; i++){ 55 readInteger(a); 56 readInteger(b); 57 addEdge(a, b); 58 addEdge(b, a); 59 } 60 } 61 inline void solve(){ 62 long long result = 0; 63 long long a, b; 64 for(int i = 1; i <= n; i++){ 65 for(int j = h[i]; j != 0; j = edge[j].next){ 66 if((j & 1) == 0) continue; 67 a = farSearch(i, j); 68 maxd = 0; 69 b = farSearch(edge[j].end, j); 70 maxd = 0; 71 result = max(result, a * b); 72 } 73 } 74 cout<<result; 75 } 76 int main(){ 77 freopen("A.input", "r", stdin); 78 freopen("A.output", "w", stdout); 79 init(); 80 solve(); 81 return 0; 82 }
描述(B 输入文件 : B.input 输出文件 : B.output)
有n 个人需要看医生, 其中第i 个人需要看医生的次数是ai, 一开始从1 到n 依次排列组成
一个等待队伍, 每个人依次看医生, 那么每个人看完医生有两种情况, 第一种情况:他
已经看够他需要看医生的次数,那么他会离开。第二种情况:他还需要看医生,那么他就
会选择重新站在队伍的最后。选择医生想知道,当他看过k 次病人之后,这个等待队伍是
什么样。
输入描述
第一行两个正整数 n 和 k (1 ≤ n ≤ 105, 0 ≤ k ≤ 1014)
第二行一共个n 正整数 a1, a2, ..., an (1 ≤ ai ≤ 109),用空格隔开。
输出描述
一行,按队列的顺序输出需要的结果,每两个数之间用空格隔开,注意不要输出多余的空
格。数据保证此时队列里至少有一个人。
样例数据
样例输入1:
3 3
1 2 1
样例输出1:
2
样例输入2:
7 10
1 3 3 1 2 3 1
样例输出2:
6 2 3
这道含金量不大,主要是这坑人的数据范围。。。O(k)的算法都会TLE,怎么办?不断把k减小,
首先从小到大排个序,然后看k次后排序后的第i个人有没有看完,看完了就把所有人已经看了的次数加上
这个数(不直接去更新,否则速度会变慢很多),一直到最后剩下次数不能使一个人离开队列
接着剩下的人每个人至少还可以看k / remain次,所以每个人至少看的次数还要加上这么多
最后就直接模拟,输出。
Code
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<cctype> 6 #include<vector> 7 using namespace std; 8 typedef bool boolean; 9 template<typename T> 10 inline void readInteger(T& u){ 11 char x; 12 while(!isdigit((x = getchar()))); 13 for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0'); 14 ungetc(x, stdin); 15 } 16 typedef class sdata{ 17 public: 18 int _count; 19 int times; 20 sdata(int times = 0, int _count = 0):times(times), _count(_count){} 21 }sdata; 22 int n; 23 long long k; 24 int* a; 25 int* b; 26 vector<sdata> qs; 27 inline void init(){ 28 readInteger(n); 29 readInteger(k); 30 a = new int[(const int)(n + 1)]; 31 b = new int[(const int)(n + 1)]; 32 for(int i = 1; i <= n; i++) 33 readInteger(a[i]); 34 memcpy(b, a, sizeof(int) * (n + 1)); 35 } 36 inline void solve(){ 37 sort(b + 1, b + n + 1); 38 int _count = 0; 39 for(int i = 1; i <= n; i++){ 40 if(i != 1 && b[i] != b[i - 1]){ 41 qs.push_back(sdata(b[i - 1], _count)); 42 _count = 0; 43 } 44 _count++; 45 } 46 qs.push_back(sdata(b[n], _count)); 47 48 int remain = n; //剩下的数量 49 int subed = 0; //已经减去的值,直接修改会浪费时间 50 for(int t = 0; (remain * 1LL * (qs[t].times - subed)) <= k && remain > 0; t++){ 51 k -= remain * 1LL * (qs[t].times - subed); 52 remain -= qs[t]._count; 53 subed += qs[t].times - subed; 54 } 55 56 if(remain == 0) return; 57 subed += k / remain; 58 k %= remain; 59 60 for(int i = 1; i <= n; i++) a[i] -= subed; 61 int i; 62 for(i = 1; i <= n && k; i++){ 63 if(a[i] <= 0) continue; 64 a[i]--; 65 k--; 66 } 67 68 for(int j = i; j <= n; j++) 69 if(a[j] > 0) printf("%d ", j); 70 for(int j = 1; j < i; j++) 71 if(a[j] > 0) printf("%d ", j); 72 } 73 int main(){ 74 freopen("B.input", "r", stdin); 75 freopen("B.output", "w", stdout); 76 init(); 77 solve(); 78 return 0; 79 }
描述(C 输入文件 : C.input 输出文件 : C.output)
有n 个任务需要你去完成,这些任务分布在3 个不同的房间,编号为1,2,3, 其中有些任务
必须在一些其他的任务完成之后才能完成。现在知道完成一个任务需要1 的时间,现在知
从房间1 到2,2 到3,3 到1 需要1 的时间,从1 到3,2 到1,3 到2 需要2 的时间。现
在你可以选择你一开始的房间,问完全所有任务的最短时间是多少,保证可以完成。
输入描述
第一行一个数 n (1 ≤ n ≤ 200) 。
第二行 n 个数, 第i 个数 ci (1 ≤ ci ≤ 3) 表示该任务所在的房间。.
接下来一共 n 行. 第 i 行的第一个数是 ki (0 ≤ ki ≤ n - 1),表示完成第i 个任务之前需要完
成的任务个数,之后 ki 个正整数表示需要提前完成的任务的编号。
输出描述
输出一个正整数表示完成任务需要是时间。
样例数据
样例输入1:
5
2 2 1 1 3
1 5
2 5 1
2 5 4
1 5
0
样例输出1:
7
首先可以发现从1走到3,还不如从1走到2再走到3,虽然在路上花费的时间是一样的,但是可能可以处理
更多的任务。像样思考,从某个房间开始到最后一个任务处理完毕的方案是唯一的,唯一影响结果的就是开始
的房间,所以枚举开始的房间然后拓扑排序就行了。
Code
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<cctype> 6 #include<queue> 7 #include<vector> 8 using namespace std; 9 typedef bool boolean; 10 template<typename T> 11 inline void readInteger(T& u){ 12 char x; 13 while(!isdigit((x = getchar()))); 14 for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0'); 15 ungetc(x, stdin); 16 } 17 typedef class Edge{ 18 public: 19 int end; 20 int next; 21 Edge(const int end = 0, const int next = 0):end(end),next(next){} 22 }Edge; 23 int ce; 24 int *h; 25 Edge* edge; 26 int* in; 27 inline void addEdge(int from, int end){ 28 edge[++ce] = Edge(end, h[from]); 29 h[from] = ce; 30 in[end]++; 31 } 32 int n; 33 int* room; 34 inline void init(){ 35 readInteger(n); 36 room = new int[(const int)(n + 1)]; 37 edge = new Edge[(const int)(n * n / 2 + 1)]; 38 h = new int[(const int)(n + 1)]; 39 in = new int[(const int)(n + 1)]; 40 memset(h, 0, sizeof(int) * (n + 1)); 41 memset(in, 0, sizeof(int) * (n + 1)); 42 for(int i = 1; i <= n; i++) 43 readInteger(room[i]); 44 for(int i = 1, k, a; i <= n; i++){ 45 readInteger(k); 46 while(k--){ 47 readInteger(a); 48 addEdge(a, i); 49 } 50 } 51 } 52 int* deg; 53 queue<int> que[3]; 54 inline int tp_sort(int s){ 55 deg = new int[(const int)(n + 1)]; 56 memcpy(deg, in, sizeof(int) * (n + 1)); 57 int _count = 0; 58 for(int i = 1; i <= n; i++) 59 if(deg[i] == 0){ 60 _count++; 61 que[room[i] - 1].push(i); 62 } 63 int status = s; 64 int result = 0; 65 while(_count){ 66 while(!que[status].empty()){ //处理完所有可以做的任务 67 int u = que[status].front(); 68 que[status].pop(); 69 for(int i = h[u]; i != 0; i = edge[i].next){ 70 deg[edge[i].end]--; 71 if(deg[edge[i].end] == 0){ 72 que[room[edge[i].end] - 1].push(edge[i].end); 73 _count++; 74 } 75 } 76 _count--; 77 } 78 if(_count == 0) break; 79 result++; 80 status++; 81 if(status > 2) status = 0; 82 } 83 delete[] deg; 84 return result + n; 85 } 86 int main(){ 87 freopen("C.input", "r", stdin); 88 freopen("C.output", "w", stdout); 89 init(); 90 int result = 0xfffffff; 91 for(int i = 0; i < 3; i++) result = min(result, tp_sort(i)); 92 printf("%d", result); 93 return 0; 94 }