D - Peaceful Teams
Time Limit: 2 sec / Memory Limit: 1024 MB
Score : 400 points
Problem Statement
There are N N N sports players.Among them, there are M M M incompatible pairs. The
i i i-th incompatible pair ( 1 ≤ i ≤ M ) (1≤i≤M) (1≤i≤M) is the A i A_i Ai-th and B i B_i Bi-th players.
You will divide the players into T T T teams. Every player must belong to exactly one team, and every team must have one or more players. Additionally, for each i = 1 , 2 , … , M i=1,2,…,M i=1,2,…,M, the A i A_i Ai -th and B i B_i Bi-th players must not belong to the same team.
Find the number of ways to satisfy these conditions. Here, two divisions are considered different when there are two players who belong to the same team in one division and different teams in the other.
Constraints
1 ≤ T ≤ N ≤ 10 1≤T≤N≤10 1≤T≤N≤10
0 ≤ M ≤ N ( N − 1 ) / 2 0≤M≤N(N−1)/2 0≤M≤N(N−1)/2
1 ≤ A i < B i ≤ N ( 1 ≤ i ≤ M ) 1≤A_i<B_i≤N (1≤i≤M) 1≤Ai<Bi≤N(1≤i≤M)
( A i , B i ) ≠ ( A j , B j ) ( 1 ≤ i < j ≤ M ) (A_i,B_i)≠(A_j,B_j) (1≤i<j≤M) (Ai,Bi)=(Aj,Bj)(1≤i<j≤M)
All input values are integers.
Input:
The input is given from Standard Input in the following format:
N N N T T T M M M
A 1 A_1 A1 B 1 B_1 B1
A 2 A_2 A2 B 2 B_2 B2
⋮ ⋮ ⋮
A M A_M AM B M B_M BM
Output
Print the answer in a single line.
Sample Input 1
5 2 2
1 3
3 4
Sample Output 1
4
The following four divisions satisfy the conditions.
No other division satisfies them, so print 4.
Sample Input 2
5 1 2
1 3
3 4
Sample Output 2
0
There may be no division that satisfies the conditions.
Sample Input 3
6 4 0
Sample Output 3
65
There may be no incompatible pair.
Sample Input 4
10 6 8
5 9
1 4
3 8
1 6
4 10
5 7
5 6
3 7
Sample Output 4
8001
共有
N
N
N 位运动员,需要将他们分为
T
T
T 组(当然每一组不能为空),但是有
M
M
M 对运动员不能与对应的运动员分在同一组,试问有几种分队方案。
需要注意的是,队伍完全不讲究顺序,如:
方案1:
队伍1:运动员1,运动员3
队伍2:运动员2
方案2:
队伍1:运动员2
队伍2:运动员3,运动员1
以上两种方案均视为同一种方案。
基本思路是搜索。但是因为不能枚举重复方案(内容一样,顺序不一样)的问题,需要:
1.按顺序枚举每一个运动员;
2.在枚举完所有可能后,设真正有
x
x
x 种不同的方案,那么枚举出来有
x
!
x!
x! 种方案(排列问题,从
x
x
x 中选
x
x
x 个,讲究顺序,即
A
x
x
A_x^x
Axx 或者
P
x
x
P_x^x
Pxx)。
所以应该将答案除以
x
!
x!
x! 。
另外,对于冲突的队员,因为同一个人可能有很多与其冲突的队员,所以我选择用vector存储。
而大致的搜索思路如下:
dfs(当前队员序号){
如果枚举完毕{
判断每一个队是否为空,否则++ans;
return;
}
将当前运动员尝试填入每一个队
如果有与其冲突的队员已在里面,则continue;
}
下面是超时代码,49个点过45个, O ( n n ) O(n^n) O(nn)。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,t,vh[11],m,a[50],b[50],x[11][11],X[11],ans;
vector<int>c[11];
void dfs(int step){
if(step>n){
for(int i=1;i<=t;++i)
if(X[i]==0)return;
++ans;
return;
}
for(int i=1;i<=t;++i){
bool f=1;
for(int j=0;j<c[step].size();++j){
for(int k=1;k<=X[i];++k){
if(c[step][j]==x[i][k]){
f=0;
break;
}
}
if(!f)break;
}
if(!f)continue;
x[i][++X[i]]=step;
dfs(step+1);
--X[i];
}
}
signed main(){
cin>>n>>t>>m;
for(int i=1;i<=m;++i){
cin>>a[i]>>b[i];
c[a[i]].push_back(b[i]);
c[b[i]].push_back(a[i]);
}
dfs(1);
for(int i=1;i<=t;++i)
ans/=i;
cout<<ans<<endl;
return 0;
}
因为对于每一个问题节点,其状态不仅在递归参数列表里,还在状态数组里,所以无法记忆化或转递归(至少我不太行)。另外因为仅超时4个点,所以考虑剪枝。
什么样的一定不可行?
是空队数量大于还剩运动员数量。
所以加一个for循环(对于
n
2
n^2
n2 的复杂度这不算什么)计算空队数量,一旦大于,return,等于的话,应当是阶乘(不过优化小,就没加)。
最后1.6s卡过啦!
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,t,vh[11],m,a[50],b[50],x[11][11],X[11],ans;
vector<int>c[11];
void dfs(int step){
if(step>n){
for(int i=1;i<=t;++i)
if(X[i]==0)return;
++ans;
return;
}
for(int i=1;i<=t;++i){
bool f=1;
for(int j=0;j<c[step].size();++j){
for(int k=1;k<=X[i];++k){
if(c[step][j]==x[i][k]){
f=0;
break;
}
}
if(!f)break;
}
if(!f)continue;
x[i][++X[i]]=step;
dfs(step+1);
--X[i];
}
}
signed main(){
cin>>n>>t>>m;
for(int i=1;i<=m;++i){
cin>>a[i]>>b[i];
c[a[i]].push_back(b[i]);
c[b[i]].push_back(a[i]);
}
dfs(1);
for(int i=1;i<=t;++i)
ans/=i;
cout<<ans<<endl;
return 0;
}