codechef Annual Parade

来源:互联网 发布:音箱测试软件 编辑:程序博客网 时间:2024/05/21 09:20

题目大意

一张n个点m条边的带边权有向图。有K组询问,每组询问给出一个整数C.

对于每组询问.你需要从图中选出若干条路径,相同的边可以经过多次.一个方案的代价是所有经过的道路(多次经过重复统计)的边权和加上起点不等于终点的路径条数乘C再加上没有经过的城市数目乘C.

对每组询问你需要计算最少代价。

2n250,1m3×104,1k104

解题思路

注意到k比较大,可能最终C不是最重要的。。。。。
假如只有一个询问的话,我们应该怎么做??!!!

我们好像看到有路径覆盖,还有Min(Cost),估计就是MaxflowMinCost.

考虑如何构图:
将每个点拆为i,i1
Si,一条流量为1,费用为0的边
i1T,一条流量为1,费用为0的边
i1i一条流量为,费用为0的边

对于一条原图中的边(u,v,cost)
uv1一条流量为,费用为cost的边

我们看一下,假如我们现在从原点增广出了一条新的增广路,他的意义是什么。。。。

1:将两条原本不相交的路径连接在了一起,那么我们就少付了一次非环的钱,CostC
2:连出了一个环,CostC

(其实你可以把一个点想象成一个超短的边。。。。。那么点没有被覆盖其实相当于不是一个环)
我们对于一个C,Cost=NC

然后我们每次增广出一条增广路对答案的贡献为PathCostC

因为我们用的是最小费用最大流算法,所以增广出来的PathCost是递增的。。。

PathCost>C的时候,我们就没有必要做了。

我们对于一个询问,我们可以二分出增广到哪一条路,然后最后全部加起来就好了

时间复杂度为O(MinCostMaxFlow(N,M)+KlogN)

参考代码

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)#define maxn 505#define maxm 300005#define mem(a,b) memset(a,b,sizeof(a))#define oo 1e9#define mo 503using namespace std;int head[maxn],t[maxm],next[maxm],v[maxm],cost[maxm],sum;int f[maxn][maxn];int n,m,q;int S,T;int a[maxn],s[maxn];void ins(int x,int y,int z,int co){    t[++sum]=y;    v[sum]=z;    cost[sum]=co;    next[sum]=head[x];    head[x]=sum;}void insert(int x,int y,int z,int co){    ins(x,y,z,co);    ins(y,x,0,-co);}int pre[maxn];int dist[maxn];bool bz[maxn];int d[mo+5];bool spfa(){    mem(dist,63);    dist[S]=0;    int l=0,r=1;    d[1]=S;    while (l!=r) {        l=(l+1) % mo;        int now=d[l];        bz[now]=0;        for(int tmp=head[now];tmp;tmp=next[tmp]) {            if (v[tmp]==0) continue;            if (dist[t[tmp]]>dist[now]+cost[tmp]) {                dist[t[tmp]]=dist[now]+cost[tmp];                pre[t[tmp]]=tmp;                if (!bz[t[tmp]]) {                    bz[t[tmp]]=1;                    r=(r+1) % mo;                    d[r]=t[tmp];                    if (dist[d[r]]<dist[d[(l+1) % mo]]) swap(d[r],d[(l+1) % mo]);                }            }        }    }    return dist[T]<oo / 10;}int main(){    scanf("%d%d%d",&n,&m,&q);    S=0;    T=n+n+1;    sum=1;    mem(f,63);    fo(i,1,m) {        int x,y,z;        scanf("%d%d%d",&x,&y,&z);        f[x][y]=min(f[x][y],z);    }    fo(i,1,n) insert(S,i,1,0),insert(i+n,T,1,0),insert(i+n,i,oo,0);    fo(i,1,n)        fo(j,1,n) {            if (f[i][j]>10000) continue;            insert(i,j+n,oo,f[i][j]);        }    while (spfa()){        a[++a[0]]=dist[T];        s[a[0]]=s[a[0]-1]+a[a[0]];        for(int tmp=T;tmp!=S;tmp=t[pre[tmp] ^ 1]) {            v[pre[tmp]]--;            v[pre[tmp] ^ 1]++;        }    }    while (q--) {        int w=0,x;        scanf("%d",&x);        int l=1,r=a[0];        while (l<=r) {            int mid=(l+r) >> 1;            if (a[mid]<x) {                w=mid;                l=mid+1;            }            else r=mid-1;        }        printf("%d\n",x*(n-w)+s[w]);    }    return 0;}
1 0
原创粉丝点击