ACM-ICPC 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; }