2014 Multi-University Training Contest 10 部分题目解题报告

Source:

http://acm.hdu.edu.cn/search.php?field=problem&key=2014%20Multi-University%20Training%20Contest%2010&source=1&searchmode=source

这场挺坑的,题面很糟糕,admin也不给力= =。。听说这套题是去年BJTU出的,出题人已经退役,所以admin不明来源(所以很逗。。)

HDOJ 4971 A simple brute force problem.

题意:n个任务,m个技术难题,每个任务有获利,每个难题有解决的费用,有的任务需要解决一些难题才能做,难题之间会有依赖关系(实际的依赖关系和题面是反的)。选一些任务,求最大获利。

分析:20个任务,可以直接枚举,但是case有100组。这题数据比较水,所以实际上枚举+剪枝就可以过。正解自然是网络流。这一块还掌握的不行,这题大概是一个最小割和权闭合图的模型,源点连边到任务,边权为获利,难题连边到汇点,边权为费用,每个任务连权无穷的边到需要解决的问题,同时依赖的问题也要连上(任务1需要难题1,难题1依赖于难题2,那么任务1需要连边到难题1和2),跑一遍最大流,总获利减去最大流就是答案。待补。

 

 

HDOJ 4972 A simple dynamic programming problem

题意:两队打篮球赛,每次进球后只记录分差,问最终比分可能的情况数。(题面又坑爹了=。=)

分析:题面坑爹导致思路各种跑偏。由于我们知道最后的分差,所以可以只考虑两队总得分的种数。思考后发现我们不确定的情况只有两种,分差从1到2以及从2到1,总分可能+1或+3,遇上这种情况可能的总分就多一种,记2到1和1到2的总数为cnt,最后如果分差为0答案就是cnt+1,否则是2cnt+2(A队高分或A队低分)。然后还要注意各种不合法情况,就是相邻分差大于3,以及分差不变(除了1)。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int T, n;
 7 int main()
 8 {
 9     scanf("%d", &T);
10     int cas = 0;
11     while(T--)
12     {
13         scanf("%d", &n);
14         bool flag = false;
15         int p = 0, t = 0, cnt = 0;
16         for (int i = 0; i < n; i++){
17             p = t;
18             scanf("%d", &t);
19             int del = abs(p-t);
20             if ((del > 3) || (del == 0 && p != 1)) flag = true;
21             if ((p == 1 && t == 2) || (p == 2 && t == 1)) cnt ++;
22         }
23         int ans = cnt;
24         if (t == 0) ans = cnt + 1;
25         else ans = 2 * cnt + 2;
26         if (flag) ans = 0;
27         printf("Case #%d: %d\n", ++cas, ans);
28     }
29     return 0;
30 }
View Code

 

 

HDOJ 4973 A simple simulation problem.

题意:开始1-n的排列,m次操作,操作D将[l, r]区间翻倍,操作Q查询[l, r]的众数出现次数。

分析:因为保证了[l, r]的长度小于10^8,所以可做了。大概就是用线段树之类的数据结构来维护,待补。

 

 

HDOJ 4974 A simple water problem

题意:一次match可能给两个选手最多加1分,现在给出n个选手的分数,问至少要多少场match。

分析:贪心考虑,每次肯定给两人都加分,也就是两两配对地打,所以是分数和/2(上取整)。还要考虑分数最大的那个人,如果他大于总和的一半,那么就让他和其他所有人配对就可以了。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int T, n, t, maxn;
 7 long long sum;
 8 int main()
 9 {
10     scanf("%d", &T);
11     int cas = 0;
12     while(T--)
13     {
14         sum = maxn = 0;
15         scanf("%d", &n);
16         for (int i = 0; i < n; i++){
17             scanf("%d", &t);
18             sum = sum + t;
19             maxn = max(maxn, t);
20         }
21         sum = (sum+1)/2;
22         long long ans;
23         if (maxn >= sum) ans = maxn;
24         else ans = sum;
25         printf("Case #%d: %lld\n", ++cas, ans);
26     }
27     return 0;
28 }
View Code

 

 

 

HDOJ 4975 A simple Gaussian elimination problem.

题意:方格填数,每个位置可以填0-9,告诉你每行和以及每列和,问是唯一解、无解还是多解。

分析:之前一次多校原题。由于这套题去年出的,所以就。做法一样,最大流,源点和行编号连边,汇点和列编号连边,分别是该行的和与该列的和,每行和每列连边,边权是9。跑一遍最大流,行和等于列和且满流有解。然后9减去残余网络上i行连j列的边的边权即是i行j列所填的数。如果能找到一个小矩形,使得顶点不是0和9与9和0,就可以多解。对应到残余网络中就是有一个环,可以调整流量。然而这题卡找环,找的算法不好就会T。标程很快,但是实际上标程对点标号1、2的做法是错误的。

我原来找环是这样的,每次枚举起点,在当前链上的点标记visiting,如果当前dfs的点能走到一个visiting的点,且当前点不是从与该点相连的边走过来的,说明形成了环。然后不管是哪个起点,一条边显然只要走一次,所以可以对边标记是否走过。按理来说复杂度是o(n+m)的。但是因为这题图是相当稠密的,所以即使每条边你走过了,你还是把这些边访问了一遍,才发现走过。可以说是o(nm)的。

一种解决的办法是双向链表,走过的边把它删了。。还有求强连通分量的,看有没有两行在一个强连通分量里,应该也是正确的,不过按理来说复杂度和dfs一样,o(n+m)但是还是要访问标记过的边。我觉得不同就在于tarjan只会dfs那些没被染色为某个scc的点,而dfs会枚举所有点作为起点。

  1 //能过本题,但是找环方法有误,标记为2的点有可能是环上的点。
  2 /*
  3 1
  4 2 3
  5 16 21
  6 18 13 6
  7 可以填
  8 9 6 1
  9 9 7 5
 10 应为多解。
 11 */
 12 #include<stdio.h>
 13 #include<string.h>
 14 
 15 int n, m, k, st, ed, esize, w, maxflow, cas;
 16 int matrix[600][600];
 17 int lv[1200], en[1200], q[1200], cur[1200];
 18 int vis[600000];
 19 int vv[1200];
 20 struct Edge{
 21     int v, w, n;
 22 } e[600000];
 23 void addedge(int u, int v, int w)
 24 {
 25     e[esize].v = v; e[esize].w = w; e[esize].n = en[u];
 26     en[u] = esize ++;
 27     e[esize].v = u; e[esize].w = 0; e[esize].n = en[v];
 28     en[v] = esize ++;
 29 }
 30 bool bfs()
 31 {
 32     memset(lv, -1, sizeof(lv));
 33     int head, tail;
 34     lv[st] = head = tail = 0;
 35     q[tail++] = st;
 36     while(head < tail)
 37     {
 38         int u = q[head++];
 39         for (int t = en[u]; t != -1; t = e[t].n){
 40             int v = e[t].v;
 41             if (lv[v] == -1 && e[t].w > 0){
 42                 lv[v] = lv[u] + 1;
 43                 q[tail++] = v;
 44                 if (v == ed) return 1;
 45             }
 46         }
 47     }
 48     return 0;
 49 }
 50 int dfs(int u, int maxf)
 51 {
 52     if (maxf == 0) return 0;
 53     if (u == ed) return maxf;
 54     int ans = 0, flow, tmp;
 55     for (int &t = cur[u]; t != -1; t = e[t].n){
 56         int v = e[t].v;
 57         if (e[t].w > 0 && lv[v] == lv[u] + 1){
 58             tmp = maxf - ans;
 59             if (e[t].w < tmp) tmp = e[t].w;
 60             flow = dfs(v, tmp);
 61             if (flow > 0){
 62                 e[t].w -= flow;
 63                 ans += flow;
 64                 e[t^1].w += flow;
 65                 if (maxf == ans) return ans;
 66             }
 67             else lv[v] = -10;
 68         }
 69     }
 70     lv[u] = -10;
 71     return ans;
 72 }
 73 bool findloop(int u, int fa)
 74 {
 75     if (vv[u] == 1) return true;
 76     if (vv[u] == 2) return false;
 77     vv[u] = 1;
 78     for (int t = en[u]; t != -1; t = e[t].n){
 79         int v = e[t].v;
 80         if (e[t].w <= 0 || v == fa || v == st || v == ed) continue;
 81         if (vis[t] == cas) continue;
 82         vis[t] = cas;
 83         if (findloop(v, u)) return true; 
 84     }
 85     vv[u] = 2;
 86     return false;
 87 }
 88 bool find()
 89 {
 90     memset(vv, 0, sizeof(vv));
 91     for (int i = 1; i <= n; i++){
 92         if (!vv[i] && findloop(i, st)) return true;
 93     }
 94     return false;
 95 }
 96 int T;
 97 int main()
 98 {
 99     memset(vis, 0, sizeof(vis));
100     cas = 0; k = 9;
101     scanf("%d", &T);
102     while(T--)
103     {
104         printf("Case #%d: ", ++cas);
105         scanf("%d%d", &n, &m);
106         memset(en, -1, sizeof(en));
107         esize = 0;
108         st = n+m+1, ed = n+m+2;
109         int sumr = 0, sumc = 0;
110         for (int i = 1; i <= n; i++){
111             scanf("%d", &w);
112             addedge(st, i, w);
113             sumr += w;
114         }
115         for (int j = n+1; j <= n+m; j++){
116             scanf("%d", &w);
117             addedge(j, ed, w);
118             sumc += w;
119         }
120         if (sumr != sumc){
121             printf("So naive!\n");
122             continue;
123         }
124         if (sumr == 0){
125             printf("So simple!\n");
126             continue;
127         }
128         for (int i = 1; i <= n; i++)
129             for (int j = n+1; j <= n+m; j++)
130                 addedge(i, j, k);
131         maxflow = 0;
132         while(bfs()){
133             for (int i = 1; i <= n+m+2; i++) cur[i] = en[i];
134             maxflow += dfs(st, 7000000);
135         }
136         if (maxflow == sumr){
137             if (find())
138                 printf("So young!\n");
139             else{
140                 printf("So simple!\n");
141             }
142         }
143         else{
144             printf("So naive!\n");
145             continue;
146         }
147     }
148     return 0;
149 }
View Code

 

 

HDOJ 4978 A simple probability problem.

题意:蒲丰投针。间距为D的平行线,一个直径为D的圆,圆内和圆上N个点,每两点连边,即针。随机放这个圆,问至少一根针与平行线相交概率。

分析:普通的蒲丰投针概率为2*l / pi*d,然后这题,思考一下发现,我们可以求一个凸包。里面的针是不用考虑的,如果和他们相交,肯定和凸包的边相交。每次和凸包相交,那么就是相交两条边(平行线交于线段端点和平行线与边重合的概率相对可以忽视)。和凸包相交的概率即是和任意两边相交的概率的和,即ΣΣPij。考虑和某两边相交的概率Pij。对于固定的边i,所有其他边j,即是和边i相交的概率Pi。所以就是ΣPi,然后ij可以互换,即Pij和Pji我们算了两次,所以还要除以2,最后就是ΣLi/pi*d,ΣLi即是凸包周长。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstdlib>
 7 #include<set>
 8 #include<map>
 9 #include<queue>
10 #include<ctime>
11 #include<string>
12 using namespace std;
13 
14 const double pi = acos(-1.0);
15 int n;
16 double d;
17 const double eps = 1e-8;
18 inline int sign(double a){
19     return a < -eps ? -1 : a > eps;
20 }
21 #define cross(p1, p2, p3) ((p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y))
22 #define crossOp(p1, p2, p3) sign(cross(p1, p2, p3))
23 struct point{
24     double x, y, id;
25     point(){}
26     point(double _x, double _y): x(_x), y(_y){}
27     bool operator < (const point &p) const{
28         int c = sign(x - p.x);
29         if (c) return c == -1;
30         return sign(y - p.y) == -1;
31     }
32     point operator -(const point &p) const{
33         return point(x - p.x, y - p.y);
34     }
35     double dot(const point &p) const{
36         return x * p.x + y * p.y;
37     }
38 };
39 
40 double dis(point a, point b)
41 {
42     return sqrt((a.x - b.x)*(a.x - b.x) + (a.y -b.y)*(a.y-b.y));
43 }
44 int onSegment(point p, point q1, point q2)
45 {
46     return crossOp(q1, q2, p) == 0 && sign((p-q1).dot(p-q2)) <= 0;
47 }
48 vector<point> convexHull(vector<point> ps)
49 {
50     int n = ps.size();
51     if (n <= 1)
52         return ps;
53     sort(ps.begin(), ps.end());
54     vector<point> qs;
55     for (int i = 0; i < n; qs.push_back(ps[i++])){
56         while(qs.size() > 1 && crossOp(qs[qs.size()-2], qs.back(), ps[i]) <= 0)
57             qs.pop_back();
58     }
59     for (int i = n - 2, t = qs.size(); i >= 0; qs.push_back(ps[i--])){
60         while((int)qs.size() > t && crossOp(qs[(int)qs.size()-2], qs.back(), ps[i]) <= 0)
61             qs.pop_back();
62     }
63     qs.pop_back();
64     return qs;
65 }
66 
67 vector<point> p, ans;
68 int T;
69 int main()
70 {
71     scanf("%d", &T);
72     int cas = 0;
73     while(T--)
74     {
75         p.clear();
76         scanf("%d %lf", &n, &d);
77         double x, y;
78         for (int i = 0; i < n; i++){
79             scanf("%lf %lf", &x ,&y);
80             p.push_back(point(x, y));
81         }
82         ans = convexHull(p);
83         double C = 0;
84         int size = ans.size();
85         for (int i = 0; i < size; i++){
86             C += dis(ans[i], ans[(i+1)%size]);
87         }
88         printf("Case #%d: %.4lf\n", ++cas, C/pi/d);
89     }
90     return 0;
91 }
View Code

 

posted @ 2014-08-22 20:36  james47  阅读(275)  评论(0编辑  收藏  举报