2015 Multi-University Training Contest 8

Hdu 5385 The path

  题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5385

  题意:有一个联通的有向图,d(x)用来记录从1点到x点的最短路径长度,d(1)=0;一个图可以称之为好图是存在一个x使得d(1)<d(2)<....d(x)>d(x+1)>...d(n), 现在你要设置每一条边的长度使得这个图是一个好图,注意,满足d(1)<d(2)<..d(n)的也是一个好图。边的长度在1~n的范围内。一定存在解决方案。

  思路:按照题解说的模拟构造就行了,如下: 我们可以采取贪心做法,一开始将1号点作为最短路径树的根,然后左边从2开始,右边从n开始,只要之前加入的点有边连向他们就加入,这样一个点加入的时间就是他的dis值,最短路径树上的父亲也可以确定,于是输出时非树边长度为n,树边长度为两个端点dis之差

  参考代码:

 1 #include <iostream>
 2 #include <cmath>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <string>
 6 #include <cstdio>
 7 #include <vector>
 8 using namespace std;
 9 #define M 300010
10 int dis[M], f[M], head[M];
11 int cnt;
12 struct node
13 {
14     int from, to, next;
15 } edge[M * 2 + 10];
16 void addedge(int a, int b)
17 {
18     edge[cnt].from = a;
19     edge[cnt].to = b;
20     edge[cnt].next = head[a];
21     head[a] = cnt++;
22 }
23 void add(int x)
24 {
25     for (int i = head[x]; i!=-1; i = edge[i].next)
26     {
27         int v = edge[i].to;
28         if (!f[v])
29             f[v] = x;
30     }
31 }
32 int main()
33 {
34     int T, n, m, a, b;
35     scanf("%d", &T);
36     while (T--)
37     {
38         memset(f, 0, sizeof(f));
39         memset(head, -1, sizeof(head));
40         f[1] = -1;
41         dis[1] = 0;
42         cnt = 0;
43         scanf("%d%d", &n, &m);
44         for (int i = 0; i < m; i++)
45         {
46             scanf("%d%d",&a, &b);
47             addedge(a, b);
48         }
49         int num = 1, l = 1, r = n;
50         while (l <= r)
51         {
52             if (f[l])
53             {
54                 add(l);
55                 dis[l++] = num++;
56             }
57             if (f[r])
58             {
59                 add(r);
60                 dis[r--] = num++;
61             }
62         }
63         for (int i = 0; i < cnt; i++)
64         {
65             a = edge[i].from;
66             b = edge[i].to;
67             if (f[b] != a)//不在最短路树上的边
68                 printf("%d
", n);
69             else
70                 printf("%d
", dis[b] - dis[a]);//最短路树上的边
71         }
72     }
73     return 0;
74 }
View Code

Hdu 5386 Cover

 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5386

题意:有一个n*n的矩阵,矩阵的每一个方格都有颜色,有以下两种操作:

    L x y: for(int i=1;i<=n;i++)color[i][x]=y;
   H x y:for(int i=1;i<=n;i++)color[x][i]=y;

   现在给你矩阵的初始状态和最终状态,m种操作,写出这些操作的顺序使的经过这些操作后,矩阵从初始状态变成最终状态;

思路:逆向思维。
   
最后一个操作肯定是把某一行或者某一列变成x,我们倒过来模拟,每次把最后一个操作找出来,即每次找到某一行或者某一列不为0的数都相同的,再找符合操作的。

参考代码:

  1 #include <iostream>
  2 #include <cmath>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <string>
  6 #include <cstdio>
  7 #include <vector>
  8 using namespace std;
  9 #define M 505
 10 #define N 105
 11 #define MOD 258280327
 12 int  n, m, h, l;
 13 #define inf 0x3f3f3f3f
 14 bool vish[M], visl[M];
 15 int G[N][N];
 16 struct node
 17 {
 18     int color, id, x;
 19 } oph[M], opl[M];
 20 int path[M];
 21 int judge(int x, int color, int dix)
 22 {
 23     if (dix == 1)
 24     {
 25         for (int i = 1; i <= n; i++)
 26         {
 27             if (G[x][i] == inf)
 28                 continue;
 29             if (G[x][i] != color)
 30                 return false;
 31         }
 32     }
 33     else
 34     {
 35         for (int i = 1; i <= n; i++)
 36         {
 37             if (G[i][x] == inf)
 38                 continue;
 39             if (G[i][x] != color)
 40                 return false;
 41         }
 42     }
 43 }
 44 void setcolor(int x, int dix)
 45 {
 46     if (dix == 1)
 47     {
 48         for (int i = 1; i <= n; i++)
 49             G[x][i] = inf;
 50     }
 51     else
 52     {
 53         for (int i = 1; i <= n; i++)
 54             G[i][x] = inf;
 55     }
 56 }
 57 void solve()
 58 {
 59     int cnt = 0;
 60     while (cnt < m)
 61     {
 62         for (int i = 0; i < h; i++)//试每一种没有使用过的纵向操作
 63         {
 64             if (vish[i])
 65                 continue;
 66             if (judge(oph[i].x, oph[i].color, 1))
 67             {
 68                 setcolor(oph[i].x, 1);
 69                 vish[i] = true;
 70                 path[cnt++] = oph[i].id;//把操作序号记录下来
 71             }
 72         }
 73         for (int i = 0; i < l; i++)
 74         {
 75             if (visl[i])
 76                 continue;
 77             if (judge(opl[i].x, opl[i].color, 2))
 78             {
 79                 setcolor(opl[i].x, 2);
 80                 visl[i] = true;
 81                 path[cnt++] = opl[i].id;
 82             }
 83         }
 84     }
 85 }
 86 int main()
 87 {
 88     int T;
 89     scanf("%d", &T);
 90     while (T--)
 91     {
 92         scanf("%d%d", &n, &m);
 93         int temp;
 94         //初始状态是不用记录的
 95         for (int i = 1; i <= n; i++)
 96             for (int j = 1; j <= n; j++)
 97                 scanf("%d", &temp);
 98         for (int i = 1; i <= n; i++)
 99         {
100             for (int j = 1; j <= n; j++)
101                 scanf("%d", &G[i][j]);
102         }
103         memset(vish, 0, sizeof(vish));//记录纵向操作是否操作过
104         memset(visl, 0, sizeof(visl));//记录横向操作是否操作过
105         char op[2];
106         int x, color;
107         h = 0;
108         l = 0;
109         for (int i = 1; i <= m; i++)
110         {
111             scanf("%s%d%d", op, &x, &color);
112             if (op[0] == 'H')
113             {
114                 oph[h].x = x;
115                 oph[h].color = color;
116                 oph[h++].id = i;
117             }
118             else
119             {
120                 opl[l].x = x;
121                 opl[l].color = color;
122                 opl[l++].id = i;
123             }
124         }
125         solve();
126         //打印路径
127         for (int i = m - 1; i >= 0; i--)
128         {
129             if (i == m - 1)
130                 printf("%d", path[i]);
131             else
132                 printf(" %d", path[i]);
133         }
134         printf("
");
135     }
136     return 0;
137 }
View Code

Hdu 5387 Clock

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5387

题意:给你一个时间,输出时分秒三个指针之间的角度(0~180),注意:实数用最简分数表示,整数直接输出。

思路:简单题。

参考代码:

 1 #include <iostream>
 2 #include <cmath>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <string>
 6 #include <cstdio>
 7 #include <vector>
 8 using namespace std;
 9 #define ang 3600
10 typedef long long ll;
11 int gcd(int a,int b){
12     return b==0?a:gcd(b,a%b);
13 }
14 void calangle(int a,int b)  
15 {  
16     int sum;  
17     if(abs(a-b)>30*6*ang)  
18         sum=60*6*ang-abs(a-b);  
19     else  
20         sum=abs(a-b);  
21     if(sum%ang)  
22     {  
23         int d=gcd(sum,ang);  
24         printf("%d/%d ",sum/d,ang/d);  
25     }  
26     else  
27         printf("%d ",sum/ang);  
28 }  
29 int main()  
30 {  
31     int i,j,k,h,m,s,t;  
32     char c;  
33     scanf("%d",&t);  
34     while(t--)  
35     {  
36         scanf("%d%c%d%c%d",&h,&c,&m,&c,&s);  
37         if(h>=12)  
38             h=h-12;  
39         int ss=ang*s*6;  
40         int mm=(60*s+ang*m)*6;  
41         int hh=((s+60*m)*5+h*ang*5)*6;  
42         calangle(hh,mm);  
43         calangle(hh,ss);  
44         calangle(mm,ss);  
45         printf("
");  
46     }  
47     return 0;  
48 }  
View Code

Hdu 5387 Zero Escape

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5389

题意:给你n个人每个人手里有一个id,然后给你两个数a和b,让你把n个人分为两组,条件是 一组人手里的id和等于a 另一组人的id和等于b,这里的和是指加起来之后对9取余,如果sum等于0 则sum等于9 否则sum = sum;还有一种情况也可以 就是所有人的id和等于a 或者等于b 相当于分为一组。

思路:

  dp[i][j]=dp[i-1][j]+dp[i-1][tmp](tmp为j-arr[i],若小于等于0,需加9调整)

    dp[i][j]含义为取前i个数字中的若干个,按给定规则,算出来的和为j的方案数

    之前有两个细节没考虑到,

    一是、当前位和我dp[i][j]中的j值相同,那么对应三种情况。

    1.当前位不取,直接取前面dp[i-1][j]的值

    2.当前位取,前面取的是dp[i-1][9]的值(因为加9,不变)

    3.当前位取,前面都不取,此种情况特殊,直接加一即可。

    其实2、3两种情况是一个数分别对应dp[i-1][0]和dp[i-1][9]的特殊情况。

    二是、当a+b的和和sum相同时,最后输出结果的时候,按理说只要输出dp[n][a]就可以了,但是这样会遗漏a中都不取,全都放在b中,而b又刚好和sum相同的情况。

参考代码:

 1 #include <iostream>
 2 #include <cmath>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <string>
 6 #include <cstdio>
 7 #include <vector>
 8 using namespace std;
 9 #define M 100005
10 #define MOD 258280327
11 int num[M];
12 int dp[M][10];
13 int cal(int n)
14 {
15     int k=0;
16     while(n)
17     {
18         k+=(n%10);
19         n/=10;
20     }
21     if(k>9)
22         return cal(k);
23     else
24         return k;
25 }
26 int main()
27 {
28     int T,a,b,n,temp,sum;
29     scanf("%d",&T);
30     while(T--)
31     {
32         memset(dp,0,sizeof(dp));
33         sum=0;
34         scanf("%d%d%d",&n,&a,&b);
35         for(int i=1;i<=n;i++)
36         {
37             scanf("%d",&num[i]);
38             num[i]=cal(num[i]);
39             sum+=num[i];
40         }
41         sum=cal(sum);
42         int s=a+b;
43         s=cal(s);
44         if(sum==s)
45         {
46             dp[1][num[1]]=1;
47             for(int i=2;i<=n;i++)
48             {
49                 for(int j=1;j<=9;j++)
50                 {
51                     temp=j-num[i];
52                     if(temp<=0)
53                         temp+=9;
54                     dp[i][j]=(dp[i-1][temp]+dp[i-1][j])%MOD;
55                 }
56             }
57             printf("%d
",(dp[n][a]+dp[n][b])%MOD);
58         }
59         else
60         {
61             int ans=0;
62             if(sum==a)
63                 ans++;
64             if(sum==b)
65                 ans++;
66             printf("%d
",ans);
67         }
68     }
69     return 0;
70 }
View Code
原文地址:https://www.cnblogs.com/PJQOOO/p/4734680.html