pat解題報告【1076】

最近一直在忙項目都沒時間好好總結寫博客,說起來真實慚愧啊。

下面就把自己最近做的幾題好好總結一下,主要記錄一些注意點,以防以後遇到再犯。

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 3
3 2 3 4
0
2 5 6
2 3 1
2 3 4
1 4
1 5
2 2 6
Sample Output:
4
5

 

這個題目的坑在題意不好理解,尤其是像我這種英語比較拙計的人。最後查了幾個單詞總算理解了題意,本質上就是做搜索。但是涉及到一個是選擇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 2
int 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-n
	for (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 2
int 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-n
	for (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重載了運算符=,否則代碼會有點囉嗦。

如果大家有什麼跟好的想法,歡迎交流!


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章