首页 > 代码库 > BZOJ2055: 80人环游世界

BZOJ2055: 80人环游世界

 

题解:

总算A掉了,各种蛋疼。。。

int main(){    freopen("input.txt","r",stdin);    freopen("output.txt","w",stdout);    n=read();m=read();s=0;t=2*n+m+1;ss=t+1;tt=t+2;sss=tt+1;    insert(s,sss,0,m,0);    for1(i,n)insert(sss,i,0,inf,0);    for1(i,n){int x=read();insert(i,i+n,x,x,0);}    for1(i,n)for2(j,i+1,n){int x=read();if(x!=-1)insert(i+n,j,0,inf,x);}    for1(i,n)insert(i+n,t,0,inf,0);    insert(t,s,0,inf,0);    mcf();    printf("%d\n",mincost);    return 0;}

s是附加源,sss是真正的源,t是真正的汇。这样构图就好了,但我们还有下界限制,那再来个ss,tt。。。居然还是费用流。。。然后这题就做完了
因为我们只需要最小费用,所以我们只需求出可行流&最小费用即可。

关于下界的处理我直接写在insert函数里。。。导致慢成翔。。。

代码:

技术分享
 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set>10 #include<queue>11 #include<string>12 #define inf 100000000013 #define maxn 20000014 #define maxm 20000015 #define eps 1e-1016 #define ll long long17 #define pa pair<int,int>18 #define for0(i,n) for(int i=0;i<=(n);i++)19 #define for1(i,n) for(int i=1;i<=(n);i++)20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)22 #define for4(i,x) for(int i=head[x],y;i;i=e[i].next)23 #define mod 100000000724 using namespace std;25 inline int read()26 {27     int x=0,f=1;char ch=getchar();28     while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}29     while(ch>=0&&ch<=9){x=10*x+ch-0;ch=getchar();}30     return x*f;31 }32 int n,m,k,mincost,tot=1,s,t,ss,tt,sss,head[maxn],d[maxn],from[2*maxm];33 bool v[maxn];34 queue<int>q;35 struct edge{int from,go,next,v,c;}e[2*maxm];36 void ins(int x,int y,int v,int c)37 {38     e[++tot]=(edge){x,y,head[x],v,c};head[x]=tot;39     e[++tot]=(edge){y,x,head[y],0,-c};head[y]=tot;40 }41 void insert(int x,int y,int l,int r,int c)42 {43     ins(ss,y,l,c);ins(x,tt,l,0);ins(x,y,r-l,c);44 }45 bool spfa()46 {47     for (int i=0;i<=sss;i++){v[i]=0;d[i]=inf;}48     q.push(ss);d[ss]=0;v[ss]=1;49     while(!q.empty())50     {51         int x=q.front();q.pop();v[x]=0;52         for (int i=head[x],y;i;i=e[i].next)53          if(e[i].v&&d[x]+e[i].c<d[y=e[i].go])54          {55             d[y]=d[x]+e[i].c;from[y]=i;56             if(!v[y]){v[y]=1;q.push(y);}57          }58     }59     return d[tt]!=inf;60 }61 void mcf()62 {63     mincost=0;64     while(spfa())65     {66         int tmp=inf;67         for(int i=from[tt];i;i=from[e[i].from]) tmp=min(tmp,e[i].v);68         mincost+=d[tt]*tmp;69         for(int i=from[tt];i;i=from[e[i].from]){e[i].v-=tmp;e[i^1].v+=tmp;}70     }71 }72 int main()73 {74     freopen("input.txt","r",stdin);75     freopen("output.txt","w",stdout);76     n=read();m=read();s=0;t=2*n+m+1;ss=t+1;tt=t+2;sss=tt+1;77     insert(s,sss,0,m,0);78     for1(i,n)insert(sss,i,0,inf,0);79     for1(i,n){int x=read();insert(i,i+n,x,x,0);}80     for1(i,n)for2(j,i+1,n){int x=read();if(x!=-1)insert(i+n,j,0,inf,x);}81     for1(i,n)insert(i+n,t,0,inf,0);82     insert(t,s,0,inf,0);83     mcf();84     printf("%d\n",mincost);85     return 0;86 }
View Code

 UPD:把边合并了之后用时成了1/4

代码:

技术分享
 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set>10 #include<queue>11 #include<string>12 #define inf 100000000013 #define maxn 20000014 #define maxm 20000015 #define eps 1e-1016 #define ll long long17 #define pa pair<int,int>18 #define for0(i,n) for(int i=0;i<=(n);i++)19 #define for1(i,n) for(int i=1;i<=(n);i++)20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)22 #define for4(i,x) for(int i=head[x],y;i;i=e[i].next)23 #define mod 100000000724 using namespace std;25 inline int read()26 {27     int x=0,f=1;char ch=getchar();28     while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}29     while(ch>=0&&ch<=9){x=10*x+ch-0;ch=getchar();}30     return x*f;31 }32 int n,m,k,mincost,tot=1,s,t,ss,tt,sss,head[maxn],d[maxn],from[2*maxm],in[maxn];33 bool v[maxn];34 queue<int>q;35 struct edge{int from,go,next,v,c;}e[2*maxm];36 void ins(int x,int y,int v,int c)37 {38     e[++tot]=(edge){x,y,head[x],v,c};head[x]=tot;39     e[++tot]=(edge){y,x,head[y],0,-c};head[y]=tot;40 }41 void insert(int x,int y,int l,int r,int c)42 {43     in[y]+=l;44     in[x]-=l;45     ins(x,y,r-l,c);46 }47 void build()48 {49     for0(i,sss)if(in[i]>0)ins(ss,i,in[i],0);50     else if(in[i]<0)ins(i,tt,-in[i],0);51 }52 bool spfa()53 {54     for (int i=0;i<=sss;i++){v[i]=0;d[i]=inf;}55     q.push(ss);d[ss]=0;v[ss]=1;56     while(!q.empty())57     {58         int x=q.front();q.pop();v[x]=0;59         for (int i=head[x],y;i;i=e[i].next)60          if(e[i].v&&d[x]+e[i].c<d[y=e[i].go])61          {62             d[y]=d[x]+e[i].c;from[y]=i;63             if(!v[y]){v[y]=1;q.push(y);}64          }65     }66     return d[tt]!=inf;67 }68 void mcf()69 {70     mincost=0;71     while(spfa())72     {73         int tmp=inf;74         for(int i=from[tt];i;i=from[e[i].from]) tmp=min(tmp,e[i].v);75         mincost+=d[tt]*tmp;76         for(int i=from[tt];i;i=from[e[i].from]){e[i].v-=tmp;e[i^1].v+=tmp;}77     }78 }79 int main()80 {81     freopen("input.txt","r",stdin);82     freopen("output.txt","w",stdout);83     n=read();m=read();s=0;t=2*n+m+1;ss=t+1;tt=t+2;sss=tt+1;84     insert(s,sss,0,m,0);85     for1(i,n)insert(sss,i,0,inf,0);86     for1(i,n){int x=read();insert(i,i+n,x,x,0);}87     for1(i,n)for2(j,i+1,n){int x=read();if(x!=-1)insert(i+n,j,0,inf,x);}88     for1(i,n)insert(i+n,t,0,inf,0);89     insert(t,s,0,inf,0);90     build();91     mcf();92     printf("%d\n",mincost);93     return 0;94 }
View Code

 

2055: 80人环游世界

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 116  Solved: 75
[Submit][Status]

Description

技术分享

Input

第一行两个正整数N,M。第二行有N个不大于M正整数,分别表示V1,V2......VN。接下来有N ¡ 1行。第i行有N ¡ i个整数,该行的第j个数表示从第i个国家到第i + j个国家的机票费(如果该值等于¡1则表示这两个国家间没有通航)。

Output

在第一行输出最少的总费用。

Sample Input

6 3
2 1 3 1 2 1
2 6 8 5 0
8 2 4 1
6 1 0
4 -1
4

Sample Output

27

HINT

1<= N < =100 1<= M <= 79

BZOJ2055: 80人环游世界