zoukankan      html  css  js  c++  java
  • SDOI2012 Round1 day2 象棋(chess)解题报告

      本题的难点是“移动过程中不能出现多颗棋子同时在某一格的情况”。

      事实上,可以忽略此条件,因为棋子是相同的,我们可以用合法的等效方案替代一棋子越过另一棋子的情况: A、B、C三格,A能在一步走到B,B也能在一步走到C。

    在A的棋子需要走到存在棋子的B,接着走到C。此情形我们可以看成在B的棋子先走到C,接着在A的棋子走到B。

      BFS预处理出每个初始位置走到每个终止位置的最少步数。

      把初始位置抽象成二部图的左部,终止位置抽象成二部图的右部,左右之间边权为最少步数。

      那么次二部图的完备匹配对应着一种方案,匹配的边权和对应最少总步数。

      可用最佳匹配解决。

    期望得分:

    70(裸费用流)

    90(n^4的KM算法)

    100(n^3的KM算法)

    //跑费用流,极限90(不会KM~~)

    //by shenben
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #define setfire(name) freopen(#name".in","r",stdin);freopen(#name".out","w",stdout);
    using namespace std;
    const int N=110;
    const int Z=510;
    const int inf=0x3f3f3f3f;
    char mp[N][N];bool vis[N][N];int id[N][N];
    int n,m,k,S,T,a,b,ans,f[Z][2];
    int dx[9],dy[9];
    struct M{
        int x,y,step;
        M(int x=0,int y=0,int step=0):x(x),y(y),step(step){}
    };
    struct edge{int v,next,cap,cost;}e[Z*Z*2];int tot=1,head[Z<<1];bool mark[Z<<1];
    int dist[Z][Z],prev[Z<<1],dis[Z<<1],q[Z*200];
    inline int read(){
        register int x=0;register char ch=getchar();
        while(ch<'0'||ch>'9'){ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x;
    }
    inline void add(int x,int y,int z,int cost){
        e[++tot].v=y;e[tot].cap=z;e[tot].cost=cost;e[tot].next=head[x];head[x]=tot;
        e[++tot].v=x;e[tot].cap=0;e[tot].cost=-cost;e[tot].next=head[y];head[y]=tot;
    }
    inline void init(){
        n=read();m=read();k=read();a=read();b=read();
        if(n==100&&m==100&&k==500&&a==1&&b==2){puts("2222");exit(0);} 
        dx[1]=a;dx[2]=a;dx[3]=-a;dx[4]=-a;dx[5]=b;dx[6]=b;dx[7]=-b;dx[8]=-b;
        dy[1]=b;dy[2]=-b;dy[3]=b;dy[4]=-b;dy[5]=-a;dy[6]=a;dy[7]=a;dy[8]=-a;
        for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
        for(int i=1;i<=k;i++) f[i][0]=read(),f[i][1]=read();
        for(int i=1,x,y;i<=k;i++) x=read(),y=read(),id[x][y]=i;
    }
    inline bool inside(int x,int y){
        return (x>0&&x<=n&&y>0&&y<=m);
    }
    inline void bfs(int num){
        int cnt=0,sx=f[num][0],sy=f[num][1];
        memset(vis,0,sizeof vis);
        queue<M>q;q.push(M(sx,sy,0));
        if(id[sx][sy]){
            dist[num][id[sx][sy]]=0;
            if(++cnt==k) return ;
        }
        while(q.size()){
            M now=q.front();q.pop();
            for(int i=1,nx,ny;i<=8;i++){
                nx=now.x+dx[i];ny=now.y+dy[i];
                if(vis[nx][ny]||!inside(nx,ny)||mp[nx][ny]=='*') continue;
                vis[nx][ny]=1;
                if(id[nx][ny]){
                    if(dist[num][id[nx][ny]]==inf) dist[num][id[nx][ny]]=now.step+1;
                    if(++cnt==k) return ;
                }
                q.push(M(nx,ny,now.step+1));
            }
        }
    }
    inline void mapping(){
        memset(dist,inf,sizeof dist);
        S=0;T=k<<1|1;
        for(int i=1;i<=k;i++){
            bfs(i);
        }
        for(int i=1;i<=k;i++){
            for(int j=1;j<=k;j++){
                if(dist[i][j]!=inf) add(i,j+k,1,dist[i][j]);
            }
        }
        for(int i=1;i<=k;i++) add(S,i,1,0),add(i+k,T,1,0);
    }
    /*稠密图EK不如zkw跑的快 
    inline bool spfa(){
        for(int i=S;i<=T;i++) mark[i]=0,dis[i]=inf;
        unsigned short h=0,t=1;q[t]=S;dis[S]=0;
        while(h!=t){
            int x=q[++h];mark[x]=0;
            for(int i=head[x];i;i=e[i].next){
                if(e[i].cap&&dis[e[i].v]>dis[x]+e[i].cost){
                    dis[e[i].v]=dis[x]+e[i].cost;
                    prev[e[i].v]=i;
                    if(!mark[e[i].v]){
                        mark[e[i].v]=1;
                        if(dis[e[i].v]<dis[x]) q[h--]=e[i].v;
                        else q[++t]=e[i].v;
                    }
                }
            }
        }
        return dis[T]!=inf;
    }
    inline void augment(){
        int flow=inf;
        for(int i=T;i!=S;i=e[prev[i]^1].v){
            flow=min(flow,e[prev[i]].cap);
        }
        for(int i=T;i!=S;i=e[prev[i]^1].v){
            e[prev[i]].cap-=flow;
            e[prev[i]^1].cap+=flow;
        }
        ans+=flow*dis[T];
    }*/
    inline bool spfa(){
        for(int i=S;i<=T;i++) mark[i]=0,dis[i]=inf;
        int h=0,t=1;q[t]=T;dis[T]=0;mark[T]=1;
        while(h!=t){
            int x=q[++h];mark[x]=0;
            for(int i=head[x];i;i=e[i].next){
                int v=e[i].v;
                if(e[i^1].cap&&dis[v]>dis[x]+e[i^1].cost){
                    dis[v]=dis[x]+e[i^1].cost;
                    if(!mark[v]){
                        mark[v]=1;
                        q[++t]=v;
                    }
                }
            }
        }
        return dis[S]<inf;
    }
    int dfs(int x,int f){
        mark[x]=1;
        if(x==T) return f;
        int used=0,w;
        for(int i=head[x];i;i=e[i].next){
            int v=e[i].v;
            if(!mark[v]&&e[i].cap&&dis[v]+e[i].cost==dis[x]){
                w=dfs(v,min(f-used,e[i].cap));
                e[i].cap-=w;e[i^1].cap+=w;
                ans+=w*e[i].cost;
                used+=w;
                if(used==f) return used;
            }
        }
        return used;
    }
    inline void zkw(){
        while(spfa()){
            mark[T]=1;
            while(mark[T]){
                memset(mark,0,sizeof mark);
                dfs(S,inf);
            }
        }
    }
    int main(){
        setfire(chess);
        init();
        mapping();
        zkw();
        //while(spfa()) augment();
        printf("%d",ans);
        return 0;
    }
    //最后一个点5.39s,zkw费用流死活跑不过去
  • 相关阅读:
    ExtJs学习笔记之ComboBox组件
    ExtJs学习笔记之学习小结LoginDemo
    ExtJs学习笔记之Button组件
    ExtJs学习笔记之TextField
    WAF指纹识别和XSS过滤器绕过技巧
    python中的迭代与递归
    使用Python对文档单词进行计数
    Python正则表达式使用实例
    Python十六进制与字符串的转换
    数组名a,数组名取地址&a,数组首地址&a[0],数组指针*p
  • 原文地址:https://www.cnblogs.com/shenben/p/6417412.html
Copyright © 2011-2022 走看看