1. 程式人生 > 其它 >暑假集訓之專題----拓撲排序題解

暑假集訓之專題----拓撲排序題解

第一單:

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 }