H题
先给出每条边的费用, q q q组询问,问当每条边的流量为 u / v u/v u/v时,跑到流量为1的最小费用
看到数据范围就知道肯定最多只能跑一次费用流,不然会直接 T T T飞
思路:求最小费用流的过程中记录每一次增广路增加的流和费用,用 m a p map map记录,最后贪心选择费用小的边进行输出(官方题解和一般的题解我一个都看不懂)
#include
#define int long long
using namespace std;
const int inf=0x3f3f3f3f,maxn=2e5+10,maxm=10005;
struct edge{
int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1;
int n,m;
map<long long,long long>mp;
inline void add_edge(int u,int v,int cost,int flow){
int ww=head[u];
e[++cnt]={ww,v,cost,flow};
head[u]=cnt;
}
int inque[maxn];
int dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){
queue<int>q;
memset(dis,0x3f,sizeof dis);
memset(flow,0x3f,sizeof flow);
memset(inque,0,sizeof inque);
q.push(s);
inque[s]=1;
dis[s]=0;
pre[t]=-1;
while(!q.empty()){
int u=q.front();
q.pop();
inque[u]=0;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(dis[v]>dis[u]+e[i].cost&&e[i].flow){
dis[v]=dis[u]+e[i].cost;
pre[v]=u;
last[v]=i;
flow[v]=min(flow[u],e[i].flow);
if(!inque[v]){
q.push(v);
inque[v]=1;
}
}
}
}
if(pre[t]!=-1)return true;
return false;
}
int maxflow,mincost;
void mcmf(int s,int t){
maxflow=0;
mincost=0;
while(spfa(s,t)){
int u=t;
// printf("maxflow==%d %d %d\n",maxflow,flow[t],flow[t]*dis[t]);
maxflow+=flow[t];
mincost+=flow[t]*dis[t];
mp[flow[t]*dis[t]]+=flow[t];
while(u!=s){
e[last[u]].flow-=flow[t];
e[last[u]^1].flow+=flow[t];
u=pre[u];
}
}
return;
}
signed main(){
while(scanf("%lld%lld",&n,&m)!=EOF){
memset(head,0,sizeof head);
cnt=1;
mp.clear();
memset(last,0,sizeof last);
int u,v,c;
for(int i=1;i<=m;i++){
scanf("%lld%lld%lld",&u,&v,&c);
add_edge(u,v,c,1);
add_edge(v,u,-c,0);
}
int q;
mcmf(1,n);
scanf("%lld",&q);
while(q--){
scanf("%lld%lld",&u,&v);
int x=0,y=v;
if(maxflow*u<v){
// printf("maxflow==%d %d %d\n",maxflow,u,v);
printf("NaN\n");
}
else{
for(auto &i:mp){
// printf("%d=======%d\n",i.first,i.second);
if(v>i.second*u){
v-=i.second*u;
x+=i.first*u;
}
else{
x+=i.first*v/i.second;
break;
}
}
int g=__gcd(x,y);
printf("%lld/%lld\n",x/g,y/g);}
}
}
return 0;
}