题目传送门
分析:
没被访问的点要C费用,跑一次路要C费用
把这两个统一一下试试。。。
那就是每次不标记起点或者终点
那就是路径覆盖了2333
二分图,x 部 i 号点与 y 部 j 号点连 i 到 j 的最短路
然后每个点都会被访问到
但是有些的代价会大于C
那些就干脆不访问了吧2333
看看费用流的函数特征
是一个单增函数
某一刻一单位流的代价大于了C,那就可以停止了
由于C会变,先求出整个的费用流函数,每次二分查找就好了
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #define maxn 2005 #define maxm 200005 #define INF 0x3f3f3f3f using namespace std; inline int getint() { int num=0,flag=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1; while(c>='0'&&c<='9')num=num*10+c-48,c=getchar(); return num*flag; } int n,m,Q; int S,T; int fir[maxn],nxt[maxm],to[maxm],cnt; int cap[maxm],cst[maxm]; int dis[maxn]; int vis[maxn],pre[maxn]; int sum[maxn],tot; int D[maxn][maxn]; inline void newnode(int u,int v,int w,long long c) {to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt,cap[cnt]=w,cst[cnt]=c;} inline void insert(int u,int v,int w,long long c) {newnode(u,v,w,c),newnode(v,u,0,-c);} inline bool spfa() { memset(dis,INF,sizeof dis);dis[S]=0; memset(pre,-1,sizeof pre); queue<int>Q;Q.push(S),vis[S]=1; while(!Q.empty()) { int u=Q.front();Q.pop();vis[u]=0; for(int i=fir[u];i;i=nxt[i]) if(cap[i]&&dis[to[i]]>dis[u]+cst[i]) { dis[to[i]]=dis[u]+cst[i];pre[to[i]]=i^1; if(!vis[to[i]])vis[to[i]]=1,Q.push(to[i]); } } return ~pre[T]; } inline int dinic() { int num=0; while(spfa()) { tot++; sum[tot]=sum[tot-1]; int mn=INF; for(int i=pre[T];i!=-1;i=pre[to[i]])mn=min(mn,cap[i^1]); int tmp=0; for(int i=pre[T];i!=-1;i=pre[to[i]])cap[i]+=mn,cap[i^1]-=mn,tmp+=cst[i^1]; sum[tot]+=tmp*mn,num+=mn; } return num; } int main() { n=getint(),m=getint(),Q=getint(); S=n*2+1,T=S+1,cnt=1; memset(D,INF,sizeof D); for(int i=1;i<=n;i++)D[i][i]=0; for(int i=1;i<=m;i++) { int u=getint(),v=getint(); D[u][v]=min(getint(),D[u][v]); } for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) D[i][j]=min(D[i][j],D[i][k]+D[k][j]); for(int i=1;i<=n;i++)insert(S,i,1,0),insert(i+n,T,1,0); for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(i^j)insert(i,j+n,1,D[i][j]); dinic(); while(Q--) { int C=getint(),l=1,r=tot,ans=0; while(l<=r) { int mid=(l+r)>>1; if(sum[mid]-sum[mid-1]<C)l=mid+1,ans=mid; else r=mid-1; } printf("%d\n",sum[ans]+(n-ans)*C); } }View Code