SOJ 2494: Appleland

Description

Long long ago, there was a country named Appleland. Appleland was consisted of N cities, some were connected by road, and all the roads were one way.

One day, the king of Appleland decided to set up K police station(s) in some city. The K police station(s) should satisfy the following conditions:

(1). Every city had the route to the city which had police station. 
(2). Once danger occured in any city, there always existed at least one police station which can send policeman to the city.

Now, the king wanted to know the total number of different way to set up the K police station(s).

Input

The fisrt line contains three number: N(1 <= N <= 100), M(1 <= M <= 20000) and K(1 <= N <= M), which stand for number of city, number of road and number of police station each. Then M line(s) following, each contains two integer i, j, it means that there is a road from city i to city j.

Output

There is one line which contain the total number of different way.

Sample Input

6 7 3
1 2
2 3
3 1
3 4
4 5
5 6
6 5

Sample Output

15

稍作分析:
简单图论加DP,挺麻烦的。我的作法如下。
先求强连通分量,将每个分量缩点,记录下每一个入度或出度为0的分量(这些分量必须建造至少一座警察局,其它的分量随意)。
求出组合数即可,组合数求法可以用DP实现,f[i][j]为前i个点建立j个警局的组合数, 
f[i][j]+=cpp[u[i]][l]*f[i-1][j-l]其中l为分配给分量i的警局数u[i]为第i的分量包含的节点数,cpp[][]为组合运算。
本题中组合数使用杨辉三角推出,但即便开long long也无法存下最极端情况(幸运的是,数据没有卡100C50,逃过一劫)。

上代码:
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <malloc.h>
  4 #define len (struct obj*)malloc(sizeof(struct obj))
  5 
  6 typedef long long lll;
  7 
  8 int min(int a,int b){
  9     if (a<b)return a;
 10     return b;
 11 }
 12 
 13 int max(int a,int b){
 14     if (a>b)return a;
 15     return b;
 16 }
 17 
 18 int s[101],ls;
 19 int u[101],lu;
 20 int time,n;
 21 
 22 struct obj{
 23     int a;
 24     struct obj*next;
 25 };
 26 
 27 typedef struct abj{
 28     int d,p,c,po;
 29     int center,num;
 30     struct obj*head;
 31     struct obj*til;
 32 }ll;
 33 
 34 struct road{
 35     int d;
 36     int r;
 37 } r[20001];
 38 
 39 ll a[101];
 40 lll f[101][101];
 41 
 42 void tarjan(int n){
 43     int t;
 44     a[n].d=a[n].p=++time;
 45     s[ls++]=n;
 46     a[n].c=1;
 47     struct obj*tp=a[n].head->next;
 48     while(tp!=NULL){
 49         if (!a[tp->a].c){
 50             tarjan(tp->a);
 51             a[n].p=min(a[n].p,a[tp->a].p);
 52         }
 53         else if (a[tp->a].c==1){
 54             a[n].p=min(a[n].p,a[tp->a].d);
 55         }
 56         tp=tp->next;
 57     }
 58     if (a[n].d==a[n].p){
 59         a[n].num=0;
 60         do{
 61             t=s[--ls];
 62             a[t].c=2;
 63             a[t].center=n;
 64             a[n].num++;
 65         }while(t!=n);
 66         a[n].po=0;
 67     }
 68 }
 69 
 70 void tarjan_main(){
 71     time=0;
 72     for (int i=1;i<=n;i++)
 73         if (!a[i].c)
 74             tarjan(i);
 75 }
 76 
 77 lll cpp[101][101];
 78 
 79 int main(){
 80     int l,i,j,m,k;
 81     scanf("%d %d %d",&n,&m,&k);
 82     for (i=1;i<=n;i++){
 83         a[i].c=0;
 84         a[i].po=-1;
 85         a[i].til=(a[i].head=len);
 86         a[i].til->next=NULL;
 87     }
 88     for (i=1;i<=m;i++){
 89         scanf("%d %d",&r[i].d,&r[i].r);
 90         a[r[i].d].til->next=len;
 91         a[r[i].d].til=a[r[i].d].til->next;
 92         a[r[i].d].til->a=r[i].r;
 93         a[r[i].d].til->next=NULL;
 94     }
 95     tarjan_main();
 96     for (i=1;i<=m;i++){
 97         if (a[r[i].d].center!=a[r[i].r].center){
 98             a[a[r[i].d].center].po|=2;
 99             a[a[r[i].r].center].po|=1;
100         }
101     }
102     lu=0;
103     cpp[0][0]=1;
104     for (i=1;i<=100;i++){
105         cpp[i][0]=1;
106         cpp[i][i]=1;
107         for (j=1;j<i;j++)cpp[i][j]=cpp[i-1][j-1]+cpp[i-1][j];
108     }
109     int sum=n;
110     for (i=1;i<=n;i++)
111         if (a[i].po==1||a[i].po==2||a[i].po==0){
112             sum-=a[i].num;
113             u[lu++]=a[i].num;
114         }
115     memset(f,0,sizeof(f));
116     for (i=1;i<=k;i++)
117         if (sum+u[0]>=i){
118             for (j=max(1,i-sum);j<=u[0]&&(i-j)<=sum&&j<=i;j++)
119                 f[1][i]+=cpp[sum][i-j]*cpp[u[0]][j];
120         }
121     for (i=2;i<=lu;i++)
122         for (j=k;j>=i;j--){
123             for (l=1;j-l>=i-1&&l<=u[i-1];l++)
124                 f[i][j]+=cpp[u[i-1]][l]*f[i-1][j-l];
125         }
126     printf("%lld\n",f[lu][k]);
127     return 0;
128 }

 

转载于:https://www.cnblogs.com/shellbase/archive/2013/03/31/2991213.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值