[sgu]185. Two shortest 网络流

我要疯啦~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

网上看见的解法都是spfa+最大流,我偏去搞最小费用最大流……

写完了觉得C++压代码就是爽……于是交,MLE,才看见空间4096K……

不死心瞎改,修改过程中反复出现了WA CE RE TLE MLE……

Edge结构体里全改short发现空间不超了,又开始RE……

然后发现有一个成员变量必须int,算了下3200+K 应该到3900K左右可以搞……交,MLE

发现因为有结构体好像也在吃空间,全改成纯数组,AC了……一共交28遍,历时9小时

现在想想貌似用临接矩阵就可以水过去了?总之题思路真的算不上难T_T只能说我太弱了,颓一个月的后果……

/*
  两遍spfa显然过不了,反例想下也很好举……
  很容易能想到网络流建模,这方面还是比较水的……
  两种寻路方法
  一种是先spfa再枚举找出来dist[a]+len(a,b)==dist[b]的边搞出来个“最短路图”
  两条路径就是两道流,最大流很容易搞……
  另一种是最小费用最大流,建图也没什么可说的……不过网上不通行说明这么做效率有问题?
  改进下应该其实算是两遍spfa的正确姿势吧,思路和朴素最大流相似,既然会走错路就加上回边
  实现起来和mcmf还是有区别的,只进行两次1-n网络增广判断下两次增量是不是都一样
  输出的话两种方法一样,直接dfs输出就行了
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
const int N=401,M=320002,INF=999999999;

struct Caf{int flow,cost;};
int g[N],q[N],prep[N],pree[N],dist[N],flow[N],tot=1,ps,pt,n,m,next[M];
short p[M],c[M],k[M];
bool v[N];
int min(int a,int b) {return a<b?a:b;}
void add(int a,int b,int cc,int d) {
  tot++; p[tot]=b; c[tot]=cc; k[tot]=d; next[tot]=g[a]; g[a]=tot;
  tot++; p[tot]=a; c[tot]=0; k[tot]=-d; next[tot]=g[b]; g[b]=tot;
}
Caf spfa() {
  int head=0,tail=1;
  memset(v,false,sizeof(v)); prep[ps]=pree[ps]=0;
  for (int i=1; i<=N; i++) dist[i]=INF;
  dist[ps]=0; q[1]=ps; flow[ps]=INF;
  while (head!=tail) {
    v[q[head=head%N+1]]=false;
    for (int tmp=g[q[head]]; tmp; tmp=next[tmp])
      if ((dist[p[tmp]]>dist[q[head]]+(int)k[tmp])&&c[tmp]) {
         dist[p[tmp]]=dist[q[head]]+(int)k[tmp];
         prep[p[tmp]]=q[head]; pree[p[tmp]]=tmp;
         flow[p[tmp]]=min(flow[q[head]],c[tmp]);
         if (!v[p[tmp]]) v[q[tail=tail%N+1]=p[tmp]]=true;
      }
  }
  if (dist[pt]==INF) return (Caf){0,0};
  for (int tmp=pt; tmp!=ps; tmp=prep[tmp])
    c[pree[tmp]]-=flow[pt], c[pree[tmp]^1]+=flow[pt];
  return (Caf){flow[pt],flow[pt]*dist[pt]};
}
Caf mcmf() {return spfa();}
void print(int pt) {
  if (pt==n) {printf("%d\n",pt); return;}
  for (int tmp=g[pt]; tmp; tmp=next[tmp])
    if ((c[tmp]==0)&&(tmp%2==0)) {
      printf("%d ",pt); c[tmp]=99;
      print(p[tmp]); return;
    }
}
int main() {
  memset(g,0,sizeof(g));
  //===============
  scanf("%d%d",&n,&m);
  while (m--) {
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    add(a,b,1,c); add(b,a,1,c);
  }
  ps=1; pt=n; Caf t1=spfa(),t2=spfa();
  if ((t1.flow==t2.flow==1)&&(t1.cost==t2.cost)) print(1),print(1);
  else puts("No solution");
  //system("pause");
  return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值