1. 程式人生 > 實用技巧 >洛谷P3068 [USACO13JAN]Party Invitations S

洛谷P3068 [USACO13JAN]Party Invitations S

題面

傳送門

分析

一道比較容易的拓撲排序題目

(當然也可以使用\(vector\)和一些奇奇怪怪的做法暴力碾過)

我們把每一個朋友組視為一個一類點,然後把每頭牛也視為二類點

然後把每頭牛代表的二類點向所有包含這頭牛的朋友組代表的一類點連雙向邊

接下來我們只需要暴力即可,每次找到當前入度為\(1\)一類點,然後把其放入隊即可(注意\(vis\)陣列標記這個一類點有沒有入隊過)

然後暴力更新就行了,拓撲排序板子

程式碼

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define ll long long
const int N=1e6+5;
int n,m,inv[N],v,len,len1,ans; 
bool vis[N];
vector<int> g[N],G[N];
void topu(){
	queue<int> que,p;
	que.push(1);vis[1]=true;
	while(!que.empty()){
		while(!que.empty()){
			int u=que.front();
			que.pop();len=G[u].size();
			for(int i=0;i<len;i++){
				v=G[u][i];
				inv[v]--;
				if(inv[v]==1){
					len1=g[v].size();
					for(int j=0;j<len1;j++){
						if(!vis[g[v][j]]){
							vis[g[v][j]]=true;
							p.push(g[v][j]);
							ans++;
						}
					}
				}
			}
		}
		que=p;
        while(!p.empty()) p.pop();
	}
	return ;
}
int main(){
	read(n),read(m);
	for(int i=1;i<=m;i++){
		read(inv[i]);
		for(int j=1;j<=inv[i];j++){
			read(v);
			G[v].push_back(i);
			g[i].push_back(v);
		}
	}
	topu();
	write(ans+1);
	return 0;
}