P4300 [AHOI2008]上学路线
题解:
看到输出的第一行,显然就是最短路,n<=500随便乱搞都可以。而我们看他要使删边过后的代价最小。那么考虑怎样删边,就是删去1-n的最短路上的边。一开始我不知道删边怎么处理,看了题解才知道,这是用的是最基础的网络流。我们先枚举所有点,然后可以把在每一个在最短路上的点建一个新图,然后这个新图的最大流(最小割)即为答案。用dinic算法即可。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=1100007; const int inf=0x7fffffff; struct node{ int nxt,to,val,cut; }edge[maxn*3]; int head[maxn],cnt; int cur[maxn]; struct node2{ int nxt,to,val; }edge2[maxn*3]; void add(int x,int y,int v,int w){ edge[++cnt].nxt=head[x]; edge[cnt].to=y; edge[cnt].val=v; edge[cnt].cut=w; head[x]=cnt; } int head2[maxn],tot=1;//改成1就行了?? void newadd(int x,int y,int v){ edge2[++tot].nxt=head2[x]; edge2[tot].to=y; edge2[tot].val=v; head2[x]=tot; } priority_queue<pair<int,int> >que; bool vis[maxn]; int dis[maxn]; int n,m; int ans1; int p[maxn],q[maxn],t[maxn],c[maxn]; void dijkstra(int x){ memset(vis,false,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); que.push(make_pair(0,x)); dis[x]=0; while(!que.empty()){ int u=que.top().second; que.pop(); if(vis[u]) continue; vis[u]=true; for(int i=head[u];i;i=edge[i].nxt){ int go=edge[i].to; if(dis[go]>dis[u]+edge[i].val){ dis[go]=dis[u]+edge[i].val; que.push(make_pair(-dis[go],go)); } } } } int dep[maxn]; queue<int> qq; int bfs(){ qq.push(1); memset(dep,0,sizeof(dep)); dep[1]=1; while(!qq.empty()){ int u=qq.front(); qq.pop(); for(int i=head2[u];i;i=edge2[i].nxt){ int v=edge2[i].to; if(edge2[i].val&&!dep[v]){ dep[v]=dep[u]+1; qq.push(v); } } } return dep[n]; } int dfs(int now,int flow){ if(now==n) return flow; for(int i=head2[now];i;i=edge2[i].nxt){ int go=edge2[i].to; if(dep[go]==dep[now]+1&&edge2[i].val){ int temp=dfs(go,min(flow,edge2[i].val)); if(temp){ edge2[i].val-=temp; edge2[i^1].val+=temp; return temp; } } } return 0; } int dinic(){ int ans=0,tmp; while(bfs()){ while(tmp=dfs(1,inf)) ans+=tmp; } return ans; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d%d",&p[i],&q[i],&t[i],&c[i]); add(p[i],q[i],t[i],c[i]);add(q[i],p[i],t[i],c[i]); } dijkstra(1); ans1=dis[n]; for(int i=1;i<=n;i++){ for(int j=head[i];j;j=edge[j].nxt){ int go=edge[j].to; if(dis[go]==dis[i]+edge[j].val){ newadd(i,go,edge[j].cut); newadd(go,i,0); } } } printf("%d\n%d\n",ans1,dinic()); return 0; }