其实之前写过一个板子,但是一点印象都没有,所以今天重写了一下,顺便把这个题当成板子就行了。
其实费用流就是把bfs换成spfa,但是中间有一个原则,就是费用优先,在费用(就是c)上跑spfa,顺便求出流量。
其实理解起来还算简单,就是先spfa找最小费用路径,然后在路径上找能跑的最大流。
题干:
Description Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑、仰卧起坐等 等,不过到目前为止,他 坚持下来的只有晨跑。 现在给出一张学校附近的地图,这张地图中包含N个十字路口和M条街道,Elaxia只能从 一 个十字路口跑向另外一个十字路口,街道之间只在十字路口处相交。Elaxia每天从寝室出发 跑到学校,保证寝室 编号为1,学校编号为N。 Elaxia的晨跑计划是按周期(包含若干天)进行的,由于他不喜欢走重复的路线,所以 在一个周期内,每天的晨跑路线都不会相交(在十字路口处),寝室和学校不算十字路 口。Elaxia耐力不太好, 他希望在一个周期内跑的路程尽量短,但是又希望训练周期包含的天 数尽量长。 除了练空手道,Elaxia其他时间 都花在了学习和找MM上面,所有他想请你帮忙为他设计 一套满足他要求的晨跑计划。 Input 第一行:两个数N,M。表示十字路口数和街道数。 接下来M行,每行3个数a,b,c,表示路口a和路口b之间有条长度为c的街道(单向)。 N ≤ 200,M ≤ 20000。 Output 两个数,第一个数为最长周期的天数,第二个数为满足最长天数的条件下最短的路程长 度。 Sample Input 7 10 1 2 1 1 3 1 2 4 1 3 4 1 4 5 1 4 6 1 2 5 5 3 6 6 5 7 1 6 7 1 Sample Output 2 11 HINT Source
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } const int N = 100005; struct node { int l,r,c,f,nxt,other; }a[N * 2]; int len = 1,lst[N],st,ed; void add(int x,int y,int f,int c) { int k1,k2 = 0; a[++len].l = x; a[len].r = y; a[len].c = c; a[len].f = f; a[len].nxt = lst[x]; lst[x] = len; k1 = len; a[++len].l = y; a[len].r = x; a[len].c = -c; a[len].f = 0; a[len].nxt = lst[y]; lst[y] = len; k2 = len; a[k1].other = k2; a[k2].other = k1; } int n,m,dis[N],flow[N],vis[N]; int pre[N],head[N],ans1 = 0,ans2 = 0; queue <int> qu; bool spfa() { clean(vis); memset(dis,70,sizeof(dis)); memset(flow,70,sizeof(flow)); memset(pre,0,sizeof(pre)); qu.push(st); vis[st] = 1; dis[st] = 0; pre[st] = 0; while(!qu.empty()) { int x = qu.front(); qu.pop(); for(int k = lst[x];k;k = a[k].nxt) { if(a[k].f == 0)continue; int y = a[k].r; if(dis[y] > dis[x] + a[k].c) { dis[y] = dis[x] + a[k].c; pre[y] = x;head[y] = k; flow[y] = min(flow[x],a[k].f); if(!vis[y]) vis[y] = 1,qu.push(y); } } vis[x] = 0; } return pre[ed]; } void mvp() { // cout<<"QAQ"<<endl; int x = flow[ed]; int i = head[ed]; ans1 ++; /*duke(j,1,2 * n) printf("%d ",head[j]);*/ i = head[ed]; while(i) { // cout<<i<<endl; ans2 += x * a[i].c; a[i].f -= x; a[a[i].other].f += x; i = head[a[i].l]; // cout<<a[i].l<<endl; } } int main() { read(n);read(m); st = 1;ed = n * 2; duke(i,1,m) { int u,v,w; read(u);read(v);read(w); add(u + n,v,1,w); } head[a[0].l] = 0; duke(i,2,n - 1) add(i,i + n,1,0); add(1,st + n,INF,0); add(n,ed,INF,0); while(spfa()) mvp(); printf("%d %d ",ans1,ans2); return 0; } /* 7 10 1 2 1 1 3 1 2 4 1 3 4 1 4 5 1 4 6 1 2 5 5 3 6 6 5 7 1 6 7 1 */