Time Limit : 1 Second Memory Limit : 65536 KB
Source : 第十届山东省ACM省赛
Problem Link : ZOJ 4124
Author : Houge Date : 2019-5-19
题目大意:
给你n个数(不知道谁大谁小)和m个关系(ai,bi),每个关系代表ai严格大于bi。问你能否通过已知推出可能的中间项k的位置。(题目保证n一定是奇数)
分析:
比赛时想用拓扑排序,结果因为菜没写出来,赛后听了学长用floyd的思路,感觉还不错便敲了一发。(不了解floyd的可先百度学习一下,不难)
·我们定义两个二维数组matrix[i][j]和num[2][n],其中matrix[i][j]=1时代表第i个数严格大于第j个数,num[0][n]代表比n小的数的个数,num[1][n]代表比n大的数的个数。
·跑一遍floyd,对于每一个通路,都可以认为它的起点严格大于终点,即给matrix[start][end]赋值为1。
·考虑一下不可能存在的情况(如样例2的第一个数严格大于自身),即图中出现自环。
·再对matrix进行遍历,更新num数组。
·最后按要求输出即可。
代码:
1 #include <bits/stdc++.h>
2
3 using namespace std;
4
5 int n,m,matrix[105][105],num[2][105],flag=0;
6
7 void floyd()
8 {
9 int i,j,k;
10
11 for(k=1;k<=n;k++) //floyd
12 for(i=1;i<=n;i++)
13 for(j=1;j<=n;j++)
14 if(matrix[i][k]&&matrix[k][j])
15 matrix[i][j]=1;
16
17 for(i=1;i<=n;i++) //判断是否有自环
18 for(j=1;j<=n;j++)
19 if(matrix[i][j]&&matrix[j][i])
20 {
21 flag=1;
22 return;
23 }
24
25 for(i=1;i<=n;i++) //维护更新num数组
26 for(j=1;j<=n;j++)
27 if(matrix[i][j])
28 {
29 num[0][i]++;
30 num[1][j]++;
31 }
32 }
33
34 int main()
35 {
36 int t;
37 scanf("%d",&t);
38 while(t--)
39 {
40 int i,a,b;
41
42 memset(matrix,0,sizeof(matrix)); //初始化
43 memset(num,0,sizeof(num));
44 flag=0;
45
46 scanf("%d%d",&n,&m);
47 for(i=0;i<m;i++) //预处理
48 {
49 scanf("%d%d",&a,&b);
50 matrix[a][b]=1;
51 }
52 floyd();
53 if(flag==0) //输出,当一个数比它大的和比它小的数的个数都小于等于n/2时,可视该项为中间项
54 {
55 for(i=1;i<=n;i++)
56 {
57 if(num[0][i]<=n/2&&num[1][i]<=n/2) printf("1");
58 else printf("0");
59 }
60 printf("
");
61 }
62 else
63 {
64 for(i=0;i<n;i++) printf("0");
65 printf("
");
66 }
67 }
68 return 0;
69 }