• ACMICPC Live Archive 3645 Objective: Berlin(没通过)


    网络流

    UVA 1161 是相同的题目

    这题网上找不到任何题解的,看上去是个最大流,但是最难搞的就是有时间限制,现在基本上能确定的就是要拆点,但是怎么拆不确定,我用了这种拆法就一直超时

    超时的原因我总结一下有几个可能。1.构图的代码太烂,可能出了什么差错但是找不出来。2.数组开小了?开大了?3.和第1个原因,然后运行EK的时候掉进了死循环或者效率太慢。4.EK太慢,要用ISAP

    超时的代码

    /*
    原本的点从0到n-1标号,但是每个点需要占用2880个空间,所以对于原来第u个顶点,怎么确定那个范围是它可以用的
    就是[u*2880 , (u+1)*2880-1]
    如果读入了点u,时间为t而且它是作为到达时间,那么实际对应的点为u*2880+t
    如果读入了点u,时间为t而且它是作为出发时间,那么实际上对应的点为u*2880+1440+t
    主要在时间转化上可能比较麻烦而且容易出错
    */
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    using namespace std;
    #define MAX 432000 //150*24*60*2=432000
    #define L 2880 //每个点需要占用的空间
    #define N 160
    #define M 5010
    #define INF 0x3f3f3f3f
    #define min(a,b) a<b?a:b
    
    char city[N][20];
    int at[N][L],dt[N][L];
    int first[10100]; //最多10000个点
    int used[MAX+10];
    int ne,nc,nv,n;
    int source,target;
    int LAST;
    struct edge{
        int u,v,cap,flow,next;
    }e[10000010];
    
    void add(int u ,int v ,int cap)
    {
        e[ne].u=u; e[ne].v=v; e[ne].cap=cap; e[ne].flow=0;
        e[ne].next=first[u]; first[u]=ne++;
        u=u^v; v=u^v; u=u^v;
        e[ne].u=u; e[ne].v=v; e[ne].cap=0; e[ne].flow=0;
        e[ne].next=first[u]; first[u]=ne++;
    }
    
    int search_city(char *s)
    {
        for(int i=0; i<nc; i++)
            if(!strcmp(s,city[i]))
                return i;
        strcpy(city[nc++],s);
        return nc-1;
    }
    
    void input()
    {
        char time[10],name[2][10];
        int hour,min,hh,mm,m;
        memset(used,-1,sizeof(used));
        memset(first,-1,sizeof(first));
        for(int i=0; i<n; i++) at[i][0]=dt[i][0]=0;
        scanf("%s%s",city[0],city[1]);
        scanf("%s",time);
        hour=(time[0]-'0')*10+(time[1]-'0');
        min=(time[2]-'0')*10+(time[3]-'0');
        LAST=hour*60+min; //按照分钟来保存时间
    
       /*
        struct vertex
        {
            int time,n;
        }vt[10100];
        */
        nc=2; ne=0; nv=0;
        scanf("%d",&m);
        while(m--)
        {
            int u,v,cap;
            int index,_index;
            scanf("%s%s%d",name[0],name[1],&cap);
            index=search_city(name[0]);
            _index=search_city(name[1]);
    
            scanf("%s",time);
            hour=(time[0]-'0')*10+(time[1]-'0');
            min=(time[2]-'0')*10+(time[3]-'0');
            u=index*2880+1440+hour*60+min; //出发点,加1440
    
            scanf("%s",time);
            hour=(time[0]-'0')*10+(time[1]-'0');
            min=(time[2]-'0')*10+(time[3]-'0');
            v=_index*2880+hour*60+min; //到达点,不加1440
    
            if(hour*60+min > LAST) continue; //直接抛弃的边
    
            if(used[u]==-1)
            {
                int t=++dt[index][0]; //出发的点;
                dt[index][t]=u; //出发的点
                used[u]=++nv; //之前没有这个点
    //            vt[nv].time=u;
    //            vt[nv].n=index;
            }
            if(used[v]==-1)
            {
                int t=++at[_index][0];
                at[_index][t]=v; //到达的点
                used[v]=++nv; //之前没有这个点
    //            vt[nv].time=v;
    //            vt[nv].n=_index;
            }
            //相当于一个映射,离散化,最后的点标号就是[0,nv-1]
    
            add(used[u] , used[v] , cap); //用离散化后的点建图
        }
        n=nc;
        for(int i=0; i<n; i++)
            for(int j=1; j<=at[i][0];j++)
                for(int k=1; k<=dt[i][0]; k++)
                    if( at[i][j]+30 <= dt[i][k])
                        add(used[at[i][j]] , used[dt[i][k]] , INF);
        source=0; target=++nv;
        for(int i=1; i<=dt[0][0];i++)
            add(source, used[dt[0][i]], INF);
        for(int i=1; i<=at[1][0]; i++)
            add(used[at[1][i]], target, INF);
    /*
        for(int i=1; i<=nv-1; i++)
            printf("%d: %d %d\n",i,vt[i].n,vt[i].time);
    
        for(int i=0; i<ne; i+=2)
        {
            printf("正边: %d %d cap=%d flow=%d\n",e[i].u,e[i].v,e[i].cap,e[i].flow);
            printf("反边: %d %d cap=%d flow=%d\n",e[i+1].u,e[i+1].v,e[i+1].cap,e[i+1].flow);
            printf("\n");
        }
    
        for(int i=0; i<n; i++)
        {
            printf("%s:\n",city[i]);
            printf("到达时间: ");
            for(int j=1; j<=at[i][0]; j++) printf("%d ",at[i][j]); printf("\n");
            printf("对应顶点: ");
            for(int j=1; j<=at[i][0]; j++) printf("%d ",used[ at[i][j] ]); printf("\n");
            printf("出发时间: ");
            for(int j=1; j<=at[i][0]; j++) printf("%d ",dt[i][j]); printf("\n");
            printf("对应顶点: ");
            for(int j=1; j<=at[i][0]; j++) printf("%d ",used[ dt[i][j] ]); printf("\n");
        }
    */
    }
    
    void EK()
    {
        int FLOW=0;
        int s=source , t=target;
        while(1)
        {
            queue<int>q;
            int a[10100],p[10100];
            memset(a,0,sizeof(a)); a[s]=INF;
            memset(p,-1,sizeof(p));
            while(!q.empty()) q.pop();
            q.push(s);
            while(!q.empty())
            {
                int u,v,cap,flow;
                u=q.front(); q.pop();
                for(int k=first[u]; k!=-1; k=e[k].next)
                {
                    v=e[k].v; cap=e[k].cap; flow=e[k].flow;
                    if(!a[v] && cap>flow)
                    {
                        a[v]=min(a[u],cap-flow);
                        p[v]=k;
                        q.push(v);
                    }
                }
            }
            if(!a[t]) break;
            //printf("_____%d_____\n",a[t]);
            for(int k=p[t]; k!=-1; k=p[e[k].u])
            {
                e[k].flow += a[t];
                e[k^1].flow -= a[t];
            }
            FLOW += a[t];
        }
        //printf("MAX_FLOW=%d\n",FLOW);
        printf("%d\n",FLOW);
    }
    
    
    int main()
    {
        while(scanf("%d",&n)!=EOF)
        {
            input();
            EK();
        }
        return 0;
    }
  • 相关阅读:
    SQL SERVER 修改表名、列名
    AgilePLM维护中,重启能解决的问题
    联通银铃小龙卡3G流量领取方法
    更改github默认分支main为master
    SQL基础:显示不存在的分组数量为0
    关于添加EF CODE First的问题
    安装Windows Service总是发生异常!
    通过Anaconda3pip安装opencvpython包失败的处理方法(亲测有效)
    jenkins安装及配置(一)
    Windows添加多个github ssh秘钥域名映射
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2996343.html
Copyright © 2020-2023  润新知