一张 n 个点 m 条边的带边权有向图。有 K 组询问,每组询问给出一个整数 C .
对于每组询问.你需要从图中选出若干条路径,相同的边可以经过多次.一个方案的代价是所有经过的道路(多次经过重复统计)的边权和加上起点不等于终点的路径条数乘 C 再加上没有经过的城市数目乘 C .
对每组询问你需要计算最少代价。
2≤n≤250,1≤m≤3×104,1≤k≤104
注意到 k 比较大,可能最终 C 不是最重要的。。。。。
假如只有一个询问的话,我们应该怎么做??!!!
我们好像看到有路径覆盖,还有 Min(Cost) ,估计就是 MaxflowMinCost .
考虑如何构图:
将每个点拆为 i , i1
S→i ,一条流量为1,费用为0的边
i1→T ,一条流量为1,费用为0的边
i1→i 一条流量为 ∞ ,费用为0的边
对于一条原图中的边 (u,v,cost)
u→v1 一条流量为 ∞ ,费用为cost的边
我们看一下,假如我们现在从原点增广出了一条新的增广路,他的意义是什么。。。。
1:将两条原本不相交的路径连接在了一起,那么我们就少付了一次非环的钱, Cost−C
2:连出了一个环, Cost−C
(其实你可以把一个点想象成一个超短的边。。。。。那么点没有被覆盖其实相当于不是一个环)
我们对于一个 C , Cost=N∗C
然后我们每次增广出一条增广路对答案的贡献为 PathCost–C
因为我们用的是最小费用最大流算法,所以增广出来的 PathCost 是递增的。。。
当 PathCost>C 的时候,我们就没有必要做了。
我们对于一个询问,我们可以二分出增广到哪一条路,然后最后全部加起来就好了
时间复杂度为 O(MinCostMaxFlow(N,M)+KlogN)
#include
#include
#include
#include
#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 503
using 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]]1) % mo]]) swap(d[r],d[(l+1) % mo]);
}
}
}
}
return dist[T]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]1;
}
else r=mid-1;
}
printf("%d\n",x*(n-w)+s[w]);
}
return 0;
}