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
%d
",ans1,dinic());
    return 0;
}
View Code