暑假集训之专题----拓扑排序题解

时间:2022-05-05
本文章向大家介绍暑假集训之专题----拓扑排序题解,主要内容包括Problem A、Problem A、Problem B、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

第一单:

Problem A

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 26   Accepted Submission(s) : 5

Problem Description

ACM-DIY is a large QQ group where many excellent acmers get together. It is so harmonious that just like a big family. Every day,many "holy cows" like HH, hh, AC, ZT, lcc, BF, Qinz and so on chat on-line to exchange their ideas. When someone has questions, many warm-hearted cows like Lost will come to help. Then the one being helped will call Lost "master", and Lost will have a nice "prentice". By and by, there are many pairs of "master and prentice". But then problem occurs: there are too many masters and too many prentices, how can we know whether it is legal or not? We all know a master can have many prentices and a prentice may have a lot of masters too, it's legal. Nevertheless,some cows are not so honest, they hold illegal relationship. Take HH and 3xian for instant, HH is 3xian's master and, at the same time, 3xian is HH's master,which is quite illegal! To avoid this,please help us to judge whether their relationship is legal or not. Please note that the "master and prentice" relation is transitive. It means that if A is B's master ans B is C's master, then A is C's master.

Input

The input consists of several test cases. For each case, the first line contains two integers, N (members to be tested) and M (relationships to be tested)(2 <= N, M <= 100). Then M lines follow, each contains a pair of (x, y) which means x is y's master and y is x's prentice. The input is terminated by N = 0. TO MAKE IT SIMPLE, we give every one a number (0, 1, 2,..., N-1). We use their numbers instead of their names.

Output

For each test case, print in one line the judgement of the messy relationship. If it is legal, output "YES", otherwise "NO".

Sample Input

3 2 0 1 1 2 2 2 0 1 1 0 0 0

Sample Output

YES

NO

裸裸的拓扑排序,只需要判断是否成环即可.......

 代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 const int maxn=105;
 5 int map[maxn][maxn];
 6 int indegree[maxn];
 7 int n,m;
 8 int main()
 9 {
10     int x,y;
11     while(scanf("%d%d",&n,&m)!=EOF&&n+m!=0)
12     {
13      memset(map,0,sizeof(map));
14      memset(indegree,0,sizeof(indegree));
15       while(m--)
16       {
17         scanf("%d%d",&x,&y);
18         x++;
19         y++;
20         if(!map[x][y])
21         {
22          map[x][y]=1;
23          indegree[y]++;
24         }
25       }
26       int j;
27       bool flag=1;
28       for(int i=1;i<=n;i++)
29       {
30           for(j=1;j<=n;j++)
31           {
32               if(indegree[j]==0)
33               {
34                 indegree[j]--;
35                 for(int k=1;k<=n;k++)
36                 {
37                   if(map[j][k])
38                     indegree[k]--;
39                 }
40                 break ;
41               }
42           }
43           if(j>n){
44             flag=0;
45             break;
46           }
47       }
48       printf(flag==0?"NOn":"YESn");
49     }
50  return 0;
51 }

Problem A

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 25   Accepted Submission(s) : 8

Problem Description

有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。

Input

输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。

Output

给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。 其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。

Sample Input

4 3 1 2 2 3 4 3

Sample Output

1 2 4 3

基础题

代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 #define maxn 505
 5 bool map[maxn][maxn];
 6 int indegree[maxn],tp[maxn],n,m;
 7 void tuopu_sort()
 8 {
 9     memset(tp,0,sizeof(tp)); //拓扑排序数组清空
10     int i,j,k=0,ll;
11     for(i=1;i<=n;i++)
12     {
13         for(j=1;j<=n;j++)
14         {
15          /*每次取出入读位0的数*/
16             if(indegree[j]==0)
17             {
18                 indegree[j]=-1;  //让他等于-1;表示舍弃掉这个数
19                 tp[k++]=j;  //放到拓扑序列中 
20                 /*进行一次循环,去掉所有这个数指向的数的一个度*/
21                 for(ll=1;ll<=n;ll++)
22                 {
23                     if(map[j][ll])  //j-->LL 表示成为map[j][ll]
24                     {
25                         indegree[ll]--;  //减少一个
26                     }
27                 }
28                 break;  // 终止,然后进行下次的查找
29             }
30         }
31         if(j>n)
32         {
33             //这表示构成了一个环
34             return ;  //之间结束即可,但是在其他的题中,不能这样...
35         }
36     }
37 }
38 int main()
39 {
40     int i=0,fx,ty;//  fx--->from x to y
41     while(scanf("%d%d",&n,&m)!=EOF)
42     {
43         memset(map,0,sizeof(map));  
44         memset(indegree,0,sizeof(indegree));
45         for(i=0;i<m;i++)
46         {
47             scanf("%d%d",&fx,&ty);
48             if(!map[fx][ty])      //防止数据重复
49             {
50               map[fx][ty]=true;  
51               indegree[ty]++;     //入度加一
52             }
53         }
54         tuopu_sort();
55         for(i=0;i<n-1;i++)
56         {
57             printf("%d ",tp[i]);
58         }
59         printf("%dn",tp[i]);
60     }
61     return 0;
62 }

Problem B

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 17   Accepted Submission(s) : 1

Problem Description

Dandelion's uncle is a boss of a factory. As the spring festival is coming , he wants to distribute rewards to his workers. Now he has a trouble about how to distribute the rewards. The workers will compare their rewards ,and some one may have demands of the distributing of rewards ,just like a's reward should more than b's.Dandelion's unclue wants to fulfill all the demands, of course ,he wants to use the least money.Every work's reward will be at least 888 , because it's a lucky number.

Input

One line with two integers n and m ,stands for the number of works and the number of demands .(n<=10000,m<=20000) then m lines ,each line contains two integers a and b ,stands for a's reward should be more than b's.

Output

For every case ,print the least money dandelion 's uncle needs to distribute .If it's impossible to fulfill all the works' demands ,print -1.

Sample Input

2 1 1 2 2 2 1 2 2 1

Sample Output

1777 -1 

用邻接表取代邻接矩阵(或者用STL取代之)

代码:

 1  /*@coder 龚细军*/
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<queue>
 6 #include<vector>  //动态的二维数组
 7 #include<iostream>
 8 using namespace std;
 9 const int maxn=10002;
10 int n,m;
11 int cnt[maxn],outd[maxn];
12 vector< vector<int> >map(maxn);
13 void tp_sort(int tol)
14 {
15  int i;
16  queue<int>st;
17  for(i=1;i<=n;i++)
18  {
19   if(!outd[i])
20   {
21    outd[i]--;
22    st.push(i);
23    break;
24   }
25  }
26  //环如何消除
27  while(!st.empty())
28  {
29   int temp=st.front();
30   vector<int>::iterator it;
31   for(it=map[temp].begin();it!=map[temp].end();it++)
32   {
33    outd[*it]--;
34    if(cnt[*it]<=cnt[temp])
35     cnt[*it]=cnt[temp]+1;
36   }
37   st.pop();
38   for(i=1;i<=n;i++)
39   {
40    if(!outd[i])
41    {
42    outd[i]--;
43    st.push(i);
44    break;
45    }
46   }
47  }
48  for(i=1;i<=n;i++)
49  {
50   if(outd[i]!=-1)
51   {
52    puts("-1");
53    return ;
54   }
55  }
56   int ans=0;
57   for(i=1;i<=n;i++)
58   {
59    ans+=cnt[i];
60   }
61   if(ans)
62      printf("%dn",n*888+ans);
63   else
64    puts("-1");
65 }
66 int main()
67 {
68  int a,b,i;
69  while(scanf("%d%d",&n,&m)!=EOF)
70  {
71   for(i=1;i<=n;i++) map[i].clear();
72   memset(outd,0,sizeof(outd));
73   memset(cnt,0,sizeof(cnt));
74   i=1;
75   while(m--)
76   {
77       scanf("%d%d",&a,&b);
78    map[b].push_back(a);
79    outd[a]++;    /*out++*/
80   }
81   tp_sort(i);
82  }
83  return 0;
84 }