[APIO 2009 ATM]强连通分量、拓扑排序、手写栈、动态规划

【算法分析】

很简单,属于送分题类型。。。

缩点然后topsort+dp就可以了~

但是比较纠结的是会爆栈。。。。比赛不知道会不会的?听说Linux的栈比较大吧。。。

【CODE】

#include #include #include const int N=501111;
const int INF=1000000000;
struct gtp{int x,y,next;}g[N];
int n,e,tot,S,head,tail,ans,stack;
int ls[N],fa[N],color[N],dep[N],list[N],du[N],w[N],F[N],v[N],edge[N],p[N];
bool ed[N];

inline void addedge(int x,int y){
     e++;
     g[e].x=x; g[e].y=y; g[e].next=ls[x]; ls[x]=e;
}

void input(){
     int m,x,y;
     scanf("%d%d",&n,&m);
     for (int i=1;i<=m;i++){
         scanf("%d%d",&x,&y);
         addedge(x,y);
     }
     for (int i=1;i<=n;i++) scanf("%d",&w[i]);
     int num;
     scanf("%d%d",&S,&num);
     for (int i=1;i<=num;i++){
         scanf("%d",&x);
         ed[x]=true;
     }
}

int gf(int k){
    if (fa[k]==k) return k;
    fa[k]=gf(fa[k]);
    return fa[k];
}

void dfs(int k){
/*    
     for (int t=ls[k];t;t=g[t].next)
       if (!dep[g[t].y]){
         dep[g[t].y]=dep[k]+1;
         dfs(g[t].y);
         if (dep[gf(g[t].y)]       }else
       if (!color[gf(g[t].y)] && dep[gf(g[t].y)]         fa[k]=fa[g[t].y];
     color[k]=1;
*/
     stack=1; p[1]=k; edge[1]=ls[k];
     while (stack){
           int &t=edge[stack];
           if (!t){
             color[p[stack]]=1;
             stack–;
             continue;
           }
           if (!dep[g[t].y]){
             dep[g[t].y]=dep[g[t].x]+1;
             stack++;
             p[stack]=g[t].y;
             edge[stack]=ls[g[t].y];
           }else
           if (!color[gf(g[t].y)] && dep[gf(g[t].y)]             fa[g[t].x]=fa[g[t].y];
             edge[stack]=g[edge[stack]].next;
           }else edge[stack]=g[edge[stack]].next;
     }
}

void tarjan(){
     for (int i=1;i<=n;i++){
         fa[i]=i;
         color[i]=0;
         dep[i]=0;
     }
     for (int i=1;i<=n;i++)
       if (!dep[i]){
         dep[i]=1;
         dfs(i);
       }
     for (int i=1;i<=n;i++){
         gf(i);
         if (fa[i]!=i){
           w[fa[i]]+=w[i];
           if (ed[i]) ed[fa[i]]=true;
         }
     }
}

void changegraph(){
     int te=e;
     e=0; memset(ls,0,sizeof(ls));
     for (int i=1;i<=te;i++)
       if (fa[g[i].x]!=fa[g[i].y])
         addedge(fa[g[i].x],fa[g[i].y]);
}

void topsort(){
     memset(du,0,sizeof(du));
     head=0; tail=0;
     for (int i=1;i<=e;i++) du[g[i].y]++;
     for (int i=1;i<=n;i++)
       if (fa[i]==i && !du[i]) list[++tail]=i;
     while (head           head++;
           for (int t=ls[list[head]];t;t=g[t].next){
             du[g[t].y]–;
             if (!du[g[t].y]) list[++tail]=g[t].y;
           }
     }
}

void dp(){
     memset(v,0,sizeof(v));
     for (int i=1;i<=n;i++) F[i]=-INF;
     ans=0;
     head=1;
     while (list[head]!=fa[S]) head++;
     F[fa[S]]=0;
     for (int k=head;k<=tail;k++){
       int &i=list[k];
       if (F[i]==-INF) continue;
       F[i]+=w[i];
       for (int t=ls[i];t;t=g[t].next)
         if (v[g[t].y]!=i){
           v[g[t].y]=i;
           if (F[i]>F[g[t].y]) F[g[t].y]=F[i];
         }
       if (ed[i] && F[i]>ans) ans=F[i];
     }   
     printf("%dn",ans);
}

int main(){
    freopen("atm.in","r",stdin);
    freopen("atm.out","w",stdout);
    input();
    tarjan();
    changegraph();
    topsort();
    dp();
}

[POJ 3273 Monthly Expense]二分答案

【题目大意】

给定一个数组A[i],1<=a[i]<=10000

求把它分成M份,每份的和不超过一个值K。

问K最小是多少?

【算法分析】

注意到A[i]都是正数,所以我们可以二分答案,然后线性贪心判断即可。

如果A[i]存在负数的话,这个算法就不正确了。

【其它】

1WA,1A。悲剧,忘了删文件。

另外一开始想了挺久的。。。最主要是读题不够仔细,没看到那个A[i]>=1

【CODE】

#include #include #include typedef long long LL;
int m,n;
int a[101111],Max=0;

bool flag(LL limit){
    int num=1;
    LL sum=a[1];
    for (int i=2;i<=n;i++)
      if (sum+a[i]>limit){
          num++;
          sum=a[i];
      }
      else sum+=a[i];
    if (num>m) return false;
    return true;
}   

int main(){
    scanf("%d%d",&n,&m);
    LL sum=0;
    for (int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        if (a[i]>Max) Max=a[i];
        sum+=a[i];
    }   
    LL l=Max,r=sum,mid;
    while (l        mid=(l+r)/2;
        if (flag(mid)) r=mid;
                  else l=mid+1;
    }
    printf("%lldn",l);
}   

[POJ1988 Cube Stacking]并差集

【题目大意】

同银河英雄传说。。。

【算法分析】

并差集之~

这题更简单,直接输出s[i]即可。

【其它】1A

。。。无意水,是在找银河英雄传说的提交网站时无意碰到的。。。

【CODE】

#include #include #include const int n=30000;
int T;
int f[31111],s[31111],tail[31111];
char c;

int gf(int x){
    if (f[x]==x) return x;
    int tf=gf(f[x]);
    s[x]+=s[f[x]];
    f[x]=tf;
    return tf;
}   

void Union(){
    int x,y;
    scanf("%d%d",&y,&x);
    gf(x); gf(y);
    s[f[y]]=1;
    int fy=f[y];
    f[f[y]]=tail[f[x]];
    tail[f[x]]=tail[fy];
}   

void Count(){
    int x;
    scanf("%d%d",&x);
    gf(x);
    printf("%dn",s[x]);
}   

int main(){
    for (int i=1;i<=n;i++){
        f[i]=i;
        s[i]=0;
        tail[i]=i;
    }   
    scanf("%d",&T);
    for (int i=1;i<=T;i++){
        c=getchar();
        while (c==’ ‘ || c==’n’) c=getchar();
        if (c==’M’) Union();
               else Count();
    }   
}   

[NOI2002 day1 银河英雄传说]并差集

【算法分析】

直接上一个并差集,然后+两个辅助数组s[i],tail[i]

s[i]表示f[i]到i的距离

tail[i]表示i所在的团的最尾部是哪个

然后维护即可。

【其它】1A

【CODE】

#include #include #include const int n=30000;
int T;
int f[31111],s[31111],tail[31111];
char c;

int gf(int x){
    if (f[x]==x) return x;
    int tf=gf(f[x]);
    s[x]+=s[f[x]];
    f[x]=tf;
    return tf;
}   

void Union(){
    int x,y;
    scanf("%d%d",&y,&x);
    gf(x); gf(y);
    s[f[y]]=1;
    int fy=f[y];
    f[f[y]]=tail[f[x]];
    tail[f[x]]=tail[fy];
}   

void Count(){
    int x,y;
    scanf("%d%d",&x,&y);
    if (gf(x)!=gf(y)){
        printf("-1n");
        return;
    }   
    int ans=abs(s[x]-s[y])-1;
    if (ans<0) ans=0;
    printf("%dn",ans);
}   

int main(){
    freopen("galaxy.in","r",stdin);
    freopen("galaxy.out","w",stdout);
    for (int i=1;i<=n;i++){
        f[i]=i;
        s[i]=0;
        tail[i]=i;
    }   
    scanf("%d",&T);
    for (int i=1;i<=T;i++){
        c=getchar();
        while (c==’ ‘ || c==’n’) c=getchar();
        if (c==’M’) Union();
               else Count();
    }   
}   

[POJ 1739 Tony’s Tour]基于连通性的状态压缩动态规划、男人8题

【题目大意】

给定一个M*N的矩阵,问从左下角经过所有非障碍点到达右下角有多少种方案?

【算法分析】

我们先把图改一下。

比如说样例

..

..

那么改成

……

.####.

.#..#.

......

这样转化以后,就变成求哈密顿回路的方案数了。

因为最外面那一圈必须走。

于是用Cdq的论文的方法解决。

【其它】1A,hash开到10003是47MS,开到473 是32MS。。。果然我的怎么说都比较慢啊。。。

【CODE】

#include #include #include #include #define cf(x) (1<<(x))
using namespace std;
const int key=473;
const int INF=0x7FFFFFFF;
typedef long long LL;
struct gtp{int y,next;}g[200000];
int m,n,ng,pg,e,mx,my;
char c[15][15];
LL fl[2][200000],ans;
int sl[2][200000];
int tot[2],ls[key];

inline void init(){e=0;memset(ls,0,sizeof(ls));}
inline void addedge(int x,int y){e++; g[e].y=y; g[e].next=ls[x]; ls[x]=e;}
inline int ChaTou(int t1,int t2){
    if (!t1 && !t2) return 0;
    if (t1) return 1;
    return 2;
}   

void add(int s,LL f){
    int st=s; if (st>=key) st%=key;
    for (int t=ls[st];t;t=g[t].next)
      if (sl[ng][g[t].y]==s){
          fl[ng][g[t].y]+=f;
          return;
      }
    sl[ng][++tot[ng]]=s;
    fl[ng][tot[ng]]=f;
    addedge(st,tot[ng]);
}

bool input(){
    ng=1; pg=0; ans=0; tot[0]=0; tot[1]=0;
    scanf("%d%d",&m,&n);
    if (!m && !n) return false;
    int i,j;
    char ch;
    memset(c,’#’,sizeof(c));
    for (i=0;i      for (j=0;j        for (ch=getchar();ch!=’#’&&ch!=’.’;ch=getchar());
        c[i+2][j+2]=ch;
      }
    m+=2; n+=4;
    for (j=0;j    for (i=0;i    for (i=0;i    c[m-1][1]=’.’; c[m-1][n-2]=’.’;
    init();
    add(1+cf((n<<1)+1),1);
    mx=0; my=0;
    for (i=0;i      for (j=0;j        if (c[i][j]==’.’){
            mx=i;
            my=j;
        }   
    return true;
}   

void No(int j){
    int k,t1,t2;
    for (k=1;k<=tot[pg];k++){
        int &s=sl[pg][k];
        if ((s&cf((j<<1)))||(s&cf((j<<1)+1))||(cf((n<<1))&s)||(cf((n<<1)+1)&s)) continue;
        add(s,fl[pg][k]);
    }   
}

void Yes(int I,int j){
    int k,lct,uct,ts,i,top,ct;
    for (k=1;k<=tot[pg];k++){
        int &s=sl[pg][k];
        LL &f=fl[pg][k];
        uct=ChaTou(s&cf((j<<1)),s&cf((j<<1)+1));
        lct=ChaTou(s&cf((n<<1)),s&cf((n<<1)+1));
        if (!j && lct) continue;
        ts=(INF-cf((j<<1))-cf((j<<1)+1)-cf((n<<1))-cf((n<<1)+1))&s;
        switch (lct){
            case 0:
                switch (uct){
                    case 0:
                        add(ts|cf((j<<1))|cf((n<<1)+1),f);
                        break;
                    case 1:
                        add(ts|cf((j<<1)),f);
                        add(ts|cf((n<<1)),f);
                        break;
                    case 2:
                        add(ts|cf((j<<1)+1),f);
                        add(ts|cf((n<<1)+1),f);
                        break;
                }   
                break;
            case 1:
                switch (uct){
                    case 0:
                        add(ts|cf((j<<1)),f);
                        add(ts|cf((n<<1)),f);
                        break;
                    case 1:
                        top=0;
                        for (i=j;;i++){
                            ct=ChaTou(s&cf((i<<1)),s&cf((i<<1)+1));
                            if (ct==1) top++;
                            if (ct==2) top–;
                            if (top==0) break;
                        }
                        add((ts^cf((i<<1)+1))|cf((i<<1)),f);
                        break;
                    case 2:
                        if (I==mx && j==my && ts==0) ans+=f;
                        break;
                }   
                break;
            case 2:
                switch (uct){
                    case 0:
                        add(ts|cf((j<<1)+1),f);
                        add(ts|cf((n<<1)+1),f);
                        break;
                    case 1:
                        add(ts,f);
                        break;
                    case 2:
                        top=0;
                        for (i=j;;i–){
                            ct=ChaTou(s&cf((i<<1)),s&cf((i<<1)+1));
                            if (ct==1) top++;
                            if (ct==2) top–;
                            if (top==0) break;
                        }   
                        add((ts^cf((i<<1)))|cf((i<<1)+1),f);
                        break;
                }   
                break;
        }   
    }   
}            

void dp(){
    for (int i=0;i      for (int j=0;j          if (!i && !j) continue;
          ng=1-ng;
          pg=1-pg;
          tot[ng]=0;
          init();
          if (c[i][j]==’#’) No(j);
                       else Yes(i,j);
      }
}   

int main(){
    while (input()){
      dp();
      cout << ans << endl;
}   
    return 0;   
}