您的位置:首页 > 其它

第七届蓝桥杯决赛 生成树计数 最后一题

2017-05-24 23:29 260 查看
第七届蓝桥杯决赛 生成树计数 最后一题 【此方法只能拿部分的分数】

生成树计数

给定一个 n*m 的格点图,包含 n 行 m 列共 n*m 个顶点,相邻的顶点之间有一条边。

【图1.png】给出了一个3*4的格点图的例子。

如果在图中删除部分顶点和其相邻的边,如上图删除第2行第3列和第3行第1列的顶点后,如【图2.png】所示。

图的生成树指包含图中的所有顶点和其中的一部分边,使得任意两个顶点之间都有由边构成的唯一路径。如果两个生成树包含有不同的边即被认为不同,则上图中共有31种不同的生成树,其中a边不选有10种,a边选有21种。

给出格点图中保留的顶点的信息,请计算该图一共有多少种不同的生成树。

【输入格式】

输入的第一行包含两个整数n, m,用空格分隔,表示格点图的行数和列数。

接下来n行,每行m个字母(中间没有分隔字符),每个字母必然是大写E或大写N,E表示对应的顶点存在,N表示对应的顶点不存在。保证存在至少一个顶点。

【输出格式】

输出一行,包含一个整数,表示生成树的个数。答案可能很大,你只需要计算答案除以1000000007的余数即可。

【样例输入】

3 4

EEEE

EENE

NEEE

【样例输出】

31

【数据规模与约定】

对于10%的数据,1<=n<=2。

对于30%的数据,1<=n<=3。

对于40%的数据,1<=n<=4。

对于50%的数据,1<=n<=5。

另有20%的数据,1<=n*m<=12。

另有10%的数据,1<=m<=15。

对于100%的数据,1<=n<=6,1<=m<=100000。

#include <stdio.h>
#include <bits/stdc++.h>
#define mod 1000000007
typedef long long ll;
using namespace std;
int n,m,cnt,ans,kk;
char s[8][100005];
int vis[700000];
int flag[700000];
int fi[700000];
class E{
public : int u,v;
};
E e[1400000];
int find(int x){return fi[x]==x?x:fi[x]=find(fi[x]);}
void dfs(int x,int sum,int bian){  //sum表示已经选择的点 bian表示已经选择的边
if(x==cnt){
if(sum==n*m-kk && bian==n*m-1-kk){
for(int i=0;i<=n*m;i++) fi[i]=i;
for(int i=0;i<cnt;i++){
if(flag[i]==1){
int a=find(e[i].u);
int b=find(e[i].v);
if(a==b) return ;
fi[a]=b;
}
}
ans++;
}
return ;
}
int u=e[x].u,v=e[x].v;
int k1=vis[u],k2=vis[v];

vis[u]=1;vis[v]=1;flag[x]=1;  //选择x这条边
dfs(x+1,sum+2-k1-k2,bian+1);
vis[u]=k1;vis[v]=k2;flag[x]=0;

dfs(x+1,sum,bian);    //不选择x这条边
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>s[i];
for(int i=1;i<=n;i++){
for(int j=0;j<m;j++){
if(s[i][j]=='E' && s[i+1][j]=='E'){
e[cnt].u=(i-1)*m+j+1;
e[cnt++].v=i*m+j+1;
}
if(s[i][j]=='E' && s[i][j+1]=='E'){
e[cnt].u=(i-1)*m+j+1;
e[cnt++].v=(i-1)*m+j+2;
}
if(s[i][j]=='N') kk++;
}
}
dfs(0,0,0);
cout<<ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息