標籤:資料結構 bfs
最近一直在忙項目都沒時間好好總結寫部落格,說起來真實慚愧啊。
下面就把自己最近做的幾題好好總結一下,主要記錄一些注意點,以防以後遇到再犯。
1076. Forwards on Weibo (30)時間限制 3000 ms
記憶體限制 32000 kB
代碼長度限制 16000 B
判題程式 Standard 作者 CHEN, Yue
Weibo is known as the Chinese version of Twitter. One user on Weibo may have many followers, and may follow many other users as well. Hence a social network is formed with followers relations. When a user makes a post on Weibo, all his/her followers can view and forward his/her post, which can then be forwarded again by their followers. Now given a social network, you are supposed to calculate the maximum potential amount of forwards for any specific user, assuming that only L levels of indirect followers are counted.
Input Specification:
Each input file contains one test case. For each case, the first line contains 2 positive integers: N (<=1000), the number of users; and L (<=6), the number of levels of indirect followers that are counted. Hence it is assumed that all the users are numbered from 1 to N. Then N lines follow, each in the format:
M[i] user_list[i]
where M[i] (<=100) is the total number of people that user[i] follows; anduser_list[i] is a list of the M[i] users that are followed by user[i]. It is guaranteed that no one can follow oneself. All the numbers are separated by a space.
Then finally a positive K is given, followed by K UserID‘s for query.
Output Specification:
For each UserID, you are supposed to print in one line the maximum potential amount of forwards this user can triger, assuming that everyone who can view the initial post will forward it once, and that only L levels of indirect followers are counted.
Sample Input:
7 33 2 3 402 5 62 3 12 3 41 41 52 2 6
Sample Output:
45
這個題目的坑在題意不好理解,尤其是像我這種英語比較拙計的人。最後查了幾個單詞總算理解了題意,本質上就是做搜尋。但是涉及到一個是選擇dfs還是bfs的問題。剛開始沒多想,感覺差不多,後來就用了dfs。
dfs需要注意的幾點:
【1】鄰居儲存資料結構的選擇,這裡用了鄰接表,比較清楚。
【2】注意不能存在迴路的情況,比如說1是4的粉絲,4也是1的粉絲。如果先1後4,那麼到4的時候就不應該回去再訪問1!也就是不能存在迴路。
【3】在不能存在迴路的基礎上,要考慮一種特殊情況,5-1-4 這時候L==0了,也就是說到了限定的最外層。這時候不能再往下搜尋,應該退回到5。但是4的鄰居此時沒有被搜尋過。若5的下一個鄰居是4,這時候4也要被訪問,因為4的鄰居可能存在沒被訪問過的點。
為瞭解決環路問題,同時兼顧【3】我們設一個點有3種狀態
#define discover 0#define cnted 1#define undsicover 2
每次訪問一個點若該點為 undsicover,那麼置為dsicover並cnt++,如果該點本身是dsicover,那麼說明存在迴路,不再繼續。一個點回退後要置為cnted。避免下次訪問被跳過,即【3】的情況。
代碼:
// pat-1076.cpp : 定義控制台應用程式的進入點。//#include "stdafx.h"#include"iostream"#include "vector"#include "algorithm"#include "fstream"using namespace std;#define discover 0#define cnted 1#define undsicover 2int cnt=0;class node{public:int id;vector<node*> neiber;int statues;node():neiber(NULL),statues(undsicover),id(-1){}};void resetall(node* an,int n){for (int i=0;i<n+1;i++){an[i].statues=undsicover;}cnt=0;}void forward(node* p,int l){ if (p->statues==discover||l==0)//避免形成迴環{return;}if ((p->statues==undsicover))//false{cnt++;//計數加一p->statues=discover;//cnted}if (p->neiber.empty())//沒有鄰居不用遍曆{return;}int len=p->neiber.size();for (int i=0;i<len;i++){ forward(p->neiber[i],l-1);//dfs}p->statues=cnted;}int main(){fstream fcin;fcin.open("C:\\Users\\Administrator\\Desktop\\456.txt");int n=0,l=0;fcin>>n>>l;node *an=new node[n+1];//編號從1-nfor (int i=1;i<=n;i++){an[i].id=i;}for (int i=1;i<=n;i++){ int temp=0,j=0;fcin>>temp;while(temp--){fcin>>j;an[j].neiber.push_back(&an[i]);//作為目標的鄰居而不是把目標作為自己的鄰居}}int k=0,index=0;fcin>>k;for(int i=0;i<k;i++){fcin>>index; forward(&an[index],l+1);cout<<cnt-1<<endl;resetall(an,n);}return 0;}
上述演算法的邏輯沒錯,但是最後一個點會逾時!!!呵呵,隨後又寫了一個bfs版本的。
// pat-1076.cpp : 定義控制台應用程式的進入點。//#include "stdafx.h"#include"iostream"#include "vector"#include "algorithm"#include "fstream"#include "queue"using namespace std;#define discover 0#define cnted 1#define undsicover 2int cnt=0;class node{public:int id;vector<node*> neiber;int statues;node():neiber(NULL),statues(undsicover),id(-1){}};void resetall(node* an,int n){for (int i=0;i<n+1;i++){an[i].statues=undsicover;}cnt=0;}void bfs(node* p,int l){ queue<vector<node*>> q;queue<vector<node*>> qq;p->statues=discover;q.push(p->neiber);while(!q.empty()){if (qq.empty()){l--;qq=q;}if (l==0){return ;}vector<node*> v=q.front();q.pop();qq.pop(); int len=v.size();for (int i=0;i<len;i++){if (v[i]->statues==undsicover){cnt++;v[i]->statues=discover;if (!v[i]->neiber.empty()&&l>0){q.push(v[i]->neiber);}}}}}int main(){fstream fcin;fcin.open("C:\\Users\\Administrator\\Desktop\\456.txt");int n=0,l=0;fcin>>n>>l;node *an=new node[n+1];//編號從1-nfor (int i=1;i<=n;i++){an[i].id=i;}for (int i=1;i<=n;i++){ int temp=0,j=0;fcin>>temp;while(temp--){fcin>>j;an[j].neiber.push_back(&an[i]);//作為目標的鄰居而不是把目標作為自己的鄰居}}int k=0,index=0;fcin>>k;for(int i=0;i<k;i++){fcin>>index;bfs(&an[index],l+1);cout<<cnt<<endl;resetall(an,n);}return 0;}
這個是可以ac的,果然遞迴是個坑啊!但是這裡涉及到一個計算bfs深度的問題。在dfs裡面這很自然,遞迴的深度就是目前所處樹的深度。但是在用stack實現的bfs演算法裡面沒有可用的量。所以這裡用了比較笨的辦法,開了兩個stack,一個是用來計數的。還好stl重載了運算子=,否則代碼會有點囉嗦。
如果大家有什麼跟好的想法,歡迎交流!