https://ac.nowcoder.com/acm/contest/5026/C
思路一:,首先通過並查集處理出所有的連通塊(限制條件),然後用表示處理第個連通塊時,選了個、個、個、個時的方案數,枚舉轉移即可,詳見代碼。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int n,m;
int a[4],f[15],vis[15],idx[15],cnt[15];
ll dp[13][13][13][13][13];
int father(int x)
{
return f[x]==x?x:f[x]=father(f[x]);
}
int main()
{
for(int i=1;i<=12;i++)
f[i]=i;
for(int i=0;i<4;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
int x,y,fx,fy;
while(m--)
{
scanf("%d%d",&x,&y);
fx=father(x),fy=father(y);
if(fx!=fy)
f[fx]=fy;
}
int id=0,idx;
for(int i=1;i<=12;i++)
{
fx=father(i);
if(!vis[fx])
vis[fx]=++id;
idx=vis[fx];
++cnt[idx];
}
dp[0][0][0][0][0]=1;
for(int i=1;i<=id;i++)
{
for(int x=0;x<=a[0];x++)
{
for(int y=0;y<=a[1];y++)
{
for(int z=0;z<=a[2];z++)
{
for(int w=0;w<=a[3];w++)
{
if(dp[i-1][x][y][z][w])
{
if(x+cnt[i]<=a[0])
dp[i][x+cnt[i]][y][z][w]+=dp[i-1][x][y][z][w];
if(y+cnt[i]<=a[1])
dp[i][x][y+cnt[i]][z][w]+=dp[i-1][x][y][z][w];
if(z+cnt[i]<=a[2])
dp[i][x][y][z+cnt[i]][w]+=dp[i-1][x][y][z][w];
if(w+cnt[i]<=a[3])
dp[i][x][y][z][w+cnt[i]]+=dp[i-1][x][y][z][w];
}
}
}
}
}
}
printf("%lld\n",dp[id][a[0]][a[1]][a[2]][a[3]]);
return 0;
}
思路二:爆搜+組合,假設在處理完所有的限制條件之後,的數量還剩下個,不妨設,那麼此時的方案數量就等於。那麼預處理出所有的連通塊後,刪去僅有個元素的連通塊(相當於該位置沒有限制條件)後,爆搜處理即可。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int n,m,num;
ll ans;
int a[4],f[15],vis[15],idx[15],cnt[15];
ll C[15][15];
int father(int x)
{
return f[x]==x?x:f[x]=father(f[x]);
}
void dfs(int j,int len)
{
if(j>len)
{
int s0=a[0],s1=s0+a[1],s2=s1+a[2];
ans+=C[num][a[0]]*C[num-s0][a[1]]*C[num-s1][a[2]]*C[num-s2][a[3]];
return ;
}
for(int i=0;i<4;i++)
{
if(a[i]>=cnt[j])
{
a[i]-=cnt[j];
dfs(j+1,len);
a[i]+=cnt[j];
}
}
}
int main()
{
for(int i=0;i<=12;i++)
C[i][0]=1;
C[1][1]=1;
for(int i=2;i<=12;i++)
for(int j=1;j<=i;j++)
C[i][j]=C[i-1][j-1]+C[i-1][j];
for(int i=1;i<=12;i++)
f[i]=i;
for(int i=0;i<4;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
int x,y,fx,fy;
while(m--)
{
scanf("%d%d",&x,&y);
fx=father(x),fy=father(y);
if(fx!=fy)
f[fx]=fy;
}
int id=0,idx;
num=12;
for(int i=1;i<=12;i++)
{
fx=father(i);
if(!vis[fx])
vis[fx]=++id;
idx=vis[fx];
++cnt[idx];
--num;
}
sort(cnt+1,cnt+1+id,greater<int>());
while(cnt[id]==1)
--id,++num;
dfs(1,id);
printf("%lld\n",ans);
return 0;
}