ZOJ 2699 Police Cities(Codeforces Gym - 100211D) SCC+DP HQG_AC的博客

ZOJ 2699

Andrew Stankevich Contest 9(Codeforces)

题意:
有一个n个点,m条边的有向图,现在有布置k个点作为警察局,要求可以通过警察局从每个城市的道路到达某个城市,从警察局到某个城市的道路可以到达每个城市。

求出布置k个警察局可能数

首先看这个数据范围就要高精度 o(╥﹏╥)o

不爽 (•́へ•́╬)

先不提高精的事。

这题看着其实挺裸的。

一看又是 S C C + D P 的模型 (SCC不会的请看裸题(Checkposts))

思考DP方程

d p [ i ] [ j ] 表示前个顶点安排j个警察局的方案数

对于没有入度或出度的点,我们单独考虑,因为这些点都必须放 P o l i c e S t a t i o n

没有入度或出度用SCC解决

d p [ i ] [ j ] = k = 0 k < j d p [ i 1 ] [ k ] c [ x ] [ j k ]

代码细看,这个题是不错的。

对于高精度不熟悉的同学,建议用 S t r u c t 定义 B i g i n t e g e r 类,之后打一下模板

注意高精度请勿输出前导零

我也打了一天才AC

Code:

include <bits/stdc++.h>
using namespace std ;
const int N = 110;

//高精模板开始 

struct bign{
    int len,s[N];
    bign(){ memset(s,0,sizeof(s));len=1;}
    bign(int num){*this=num;}
    bign(char *num){*this=num;}
    bign operator =(int num){
        char c[N];
        sprintf(c,"%d",num);
        *this=c;
        return *this;
    }
    bign operator =(const char *num){
        len=strlen(num);
        for (int i=0;i<len;i++) s[i]=num[len-1-i]-'0';
        return *this;
    }
    string str(){
        string res="";
        for (int i=0;i<len;i++) res=(char)(s[i]+'0')+res;
        return res;
    }
    void clean(){
        while (len>1&&!s[len-1]) len--;
    }
    bign operator +(const bign &b){
        bign c;    
        c.len=0;
        for (int i=0,g=0;g||i<len||i<b.len;i++){
            int x=g;
            if (i<len) x+=s[i];
            if (i<b.len) x+=b.s[i];
            c.s[c.len++]=x%10;
            g=x/10;
        }
        return c;
    }
    bign operator -(const bign &b){
        bign c;
        c.len=0;
        int x;     
        for (int i=0,g=0;i<len;i++){
            x=s[i]-g;
            if (i<b.len) x-=b.s[i];
            if (x>=0) g=0;
            else{          
                x+=10;
                g=1;
            };
            c.s[c.len++]=x;
        }
        c.clean();
        return c;
    }
    bign operator *(const bign &b){
        bign c;
        c.len=len+b.len;
        for (int i=0;i<len;i++) for (int j=0;j<b.len;j++) c.s[i+j]+=s[i]*b.s[j];
        for (int i=0;i<c.len-1;i++) { c.s[i+1]+=c.s[i]/10; c.s[i]%=10; }
        c.clean();
        return c;  
    }
    bool operator <(const bign &b){
        if (len!=b.len) return len<b.len;
        for (int i=len-1;i>=0;i--)
             if (s[i]!=b.s[i]) return s[i]<b.s[i];
        return false;
    }
    bign operator +=(const bign &b){
        *this=*this+b;
        return *this;
    }
    bign operator -=(const bign &b){
        *this=*this-b;
        return *this;
    }  
};
istream& operator >>(istream &in,bign &x){
  string s;
  in>>s;
  x=s.c_str();
  return in;
}
ostream& operator <<(ostream &out,bign &x){
    out<<x.str();
    return out;
}

//高精大模板就此结束 

vector <int> G[N],nod,hd ;//nod存储没有d的点 
stack <int> S ;
int link[N],din[N],dout[N],dfn[N],low[N],sd[N] ;
//link[i]表示SCC i有多少个点,din和dout分别表示i的入度和出度
//dfn和low是Trajan里要干的
//sd表示缩点
bool vis[N] ;
bign dp[N][N],c[N][N] ; 
int n,m,K,cnt,tot ;

void tarjan(int now){ //tarjan ---> scc 
    dfn[now]=low[now]=++tot ;
    vis[now]=true;S.push(now) ;
    for (int i=0;i<G[now].size();i++){
        int to=G[now][i] ;
        if (!dfn[to]){
            tarjan(to) ;
            low[now]=min(low[now],low[to]) ;
        }
        else if (vis[to]) low[now]=min(low[now],dfn[to]) ;
    }
    if (dfn[now]==low[now]){
        sd[now]=++cnt ;
        link[cnt]++ ;
        vis[now]=false ;
        while(S.top()!=now){
            sd[S.top()]=cnt; 
            link[cnt]++ ;
            vis[S.top()]=false ;
            S.pop() ;
        } 
        S.pop() ;
    }
}
void init_c(){ //预处理出C数组
    for(int i=0;i<N;i++){
        c[i][0]=c[i][i]=1 ;
        for (int j=1;j<i;j++) c[i][j]=c[i-1][j-1]+c[i-1][j] ;
    }
}
void init(){
    tot=cnt=0 ;
    memset(dfn,0,sizeof(dfn)) ;
    memset(low,0,sizeof(low)) ;
    memset(vis,0,sizeof(vis)) ;
    memset(sd,0,sizeof(sd)) ; 
    memset(link,0,sizeof(link)) ;
    memset(din,0,sizeof(din)) ;
    memset(dout,0,sizeof(dout)) ; 
    memset(dp,0,sizeof(dp)) ;
    nod.clear() ;
    hd.clear() ;
    for (int i=0;i<=N;i++) G[i].clear() ;
    while (!S.empty()) S.pop() ;
}

int main(){
    ios::sync_with_stdio(false) ;
    init_c() ; 
    while(~scanf("%d%d%d",&n,&m,&K)){ 
        init() ;
        for (int i=1;i<=m;i++){
            int x,y ; 
            scanf("%d%d",&x,&y) ;
            G[x].push_back(y) ;
        }
        for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i) ;
        dp[0][0]=1 ;
        for (int i=1;i<=n;i++){
            for (int j=0;j<G[i].size();j++){
                int v=G[i][j] ;
                if (sd[i]==sd[v]) continue ;
                    din[sd[v]]++;
                    dout[sd[i]]++ ;

            }
        }
        for (int i=1;i<=cnt;i++)
        if (!din[i] || !dout[i]) nod.push_back(i) ;
        else hd.push_back(i) ;
        for (int i=1;i<=nod.size();i++)
        for (int j=1;j<=K;j++)
        for (int k=j-1;k>=0 && j-k<=link[nod[i-1]];k--)
        dp[i][j]+=dp[i-1][k]*c[link[nod[i-1]]][j-k] ;
        for (int i=nod.size()+1,t=0;i<=cnt;i++,t++)
        for (int j=nod.size();j<=K;j++)
        for (int k=nod.size();k<=j;k++)
        dp[i][j]+=dp[i-1][k]*c[link[hd[t]]][j-k] ;
        cout<<dp[cnt][K]<<endl<<endl ;
    }
} 

猜你喜欢

转载自blog.csdn.net/hqg_ac/article/details/81081342
今日推荐