[bzoj3579][亂搞]破冰派對

Description

由於計算機系的同學們都很宅,很多同學雖然身在一個系,但是入學很久還是相互不認識。學生會主席小Y希望舉辦一次破冰派對,要讓同學們多從寢室裏走出來參加娛樂活動,也要讓儘量多不認識的同學們通過活動相互認識。自然的,如果參加活動的同學互相都不認識,那便是極好的。?
  要辦一次成功的派對是很不容易的,不光需要有同學參加,優秀的工作人員也是必不可少的。他們需要爲派對的籌辦付出很多的努力,因此一個和諧的團隊是非常重要的。小Y希望所有工作人員都是相互認識的。
  計算機系一共有N個同學,所有同學從1到N編號。有M對同學相互認識,而其餘的同學相互不認識。
  小Y希望從中選出一些工作人員組成工作團隊,讓這個工作團隊負責活動的組織,而其餘的所有非工作人員,就自然都成爲了活動的參與者。小Y要求:
  1、工作團隊的成員必須相互認識;   2、參與活動的同學必須相互不認識;   3、至少有一個同學參與活動,也至少有一個同學是工作人員。
  小Y想知道,一共有多少種工作團隊的選擇方案呢?

Input

第一行讀入一個整數T,表示測試數據的組數。接下來T組數據,每組數據格式如下:   第一行包含兩個整數N和M。
  接下來M行,第i行包含兩個不同的,在1到N之間的整數xi,yi,表示編號爲xi和yi的同學相互認識。
  輸入數據保證,在每一組測試數據中,任意兩個同學之間的朋友關係都不會被列出兩次。

Output

對於每一組測試數據輸出一行一個整數,表示可行的方案總數,模1000003的餘數。

Sample Input

2

1 0

4 4

1 2

1 3

2 3

3 4

Sample Output

0

3

HINT

對於100%的數據滿足1 ≤ N ≤ 1000,0 ≤ M ≤ N^2,1 ≤ T ≤ 6。

題解

這不是一個搜索題
題目讓你把他分成兩個塊,滿足一個塊之間兩兩有邊而另一個塊之間兩兩無邊,問方案數
如果我們能弄出來一個合法解,可以知道,剩餘的解只有可能有三種情況
1:在未選擇的圖選擇一個加入
2:在選擇的圖中選擇一個拿出
3:在未選擇的圖中選擇一個拿入並在選擇的圖中選擇一個拿出
證明是顯然的
然後我們考慮如何弄出一個合法解
把點按度數從大到小排序,這裏需要一個結論就是,如果一個度數大的點沒有在選擇的圖中,那麼剩餘度數比他小的點全部都不能在選擇的圖中
因爲一個點如果沒選,那麼與之相連的全部都要被選中,又知道剩餘加入的點一定要至少與這些點有邊,但是他們的度數比我當前這個度數小,所以不可能再被加入了
那麼從大到小加入點直到做出一個合法的方案,剩餘按上面調整即可
複雜度O(m+nlogn)O(m+nlogn)
這個題其實允許了n2n^2,那麼其實還可以2sat2-sat直接n2n^2暴力建邊求一個合法解

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(LL x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=1005;
struct edge{int x,y,next;}a[MAXN*MAXN*2];int len,last[MAXN];
void ins(int x,int y){len++;a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;}
int n,m,cal[MAXN],du[MAXN],fac[MAXN];
bool cmp(int n1,int n2){return du[n1]>du[n2];}
vector<int> A,B;
bool in[MAXN];
int vi[MAXN],tim;
int main()
{
//	freopen("a.in","r",stdin);
	int CASE=read();
	while(CASE--)
	{
		len=0;memset(last,0,sizeof(last));
		memset(du,0,sizeof(du));A.clear();
		memset(in,false,sizeof(in));memset(vi,0,sizeof(vi));tim=0;
		n=read();m=read();
		for(int i=1;i<=m;i++)
		{
			int x=read(),y=read();
			ins(x,y);ins(y,x);
			du[x]++;du[y]++;
		}
		for(int i=1;i<=n;i++)fac[i]=i;
		int lin=m;
		sort(fac+1,fac+1+n,cmp);
		int cnt=0;bool ok=true;
		for(int i=1;i<=n;i++)
		{
			int sum=0;
			for(int k=last[fac[i]];k;k=a[k].next)
			{
				int y=a[k].y;
				if(!in[y])m--;
				else sum++;
			}
			if(sum==cnt)A.push_back(fac[i]),in[fac[i]]=true,cnt++;
			else if(m)break;
		}
		if(m){puts("0");continue;}
		LL as=0,plan=1;
		for(int i=1;i<=n;i++)if(in[i])as+=cal[i];
		LL total=as;
		if(cnt==n)plan=0;
	//	if(!lin)as=max(as,0LL),plan++;
		for(int i=1;i<=n;i++)if(!in[i])
		{
			int sum=0;tim++;
			for(int k=last[i];k;k=a[k].next)
			{
				int y=a[k].y;
				if(in[y])sum++,vi[y]=tim;
			}
			if(sum==cnt-1)
			{
				int u;
				for(int j=0;j<A.size();j++)if(vi[A[j]]!=tim){u=A[j];break;}
				as=max(as,total-cal[u]+cal[i]);plan++;
			}
			else if(sum==cnt&&cnt!=n-1)as=max(as,total+cal[i]),plan++;
		}
		for(int i=1;i<=n;i++)if(in[i])
		{
			bool tf=true;
			for(int k=last[i];k;k=a[k].next)
			{
				int y=a[k].y;
				if(!in[y]){tf=false;break;}
			}
			if(tf&&cnt!=1)as=max(as,total-cal[i]),plan++;
		}
	//	if(CASE&1)
		pr2(plan%1000003);
	}
//	else pr2(as);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章