这道题刚开始想了很久,而且之前一直不明白dicnic既然已经求了阻塞流,为什么还需要反向弧呢,现在如图:
2和3是一层,4和5是一层,然后你要是走1->2->4->6的话,如果没有反向弧,你会发现最大流是2,没有增广路了,而当有了反向弧之后,你还可以走1->3->4->2->5->6,以前总听别人说有反向弧,然而一直没找到合适的例子,今天终于让我找到了,非常开心
下面说一下今天这道题,这个题也是听了学姐的思路才会的,首先是第一问,求最少去掉几条边使其不能构成最短路,最少是说最小割即最大流,然后分别求以1为原点和以n为原点的最短路,然后给的边,如果两点分别到1和n的最短路加上两点间距离等于1到n的最短路,那么这条边就有可能是最短路上的边,把它加到一个数组里,去进行最大流,需要强调的是,可能一条边的起点u,终点v,u到1的距离比v到1的距离远,那么交换他们,然后跑一边最大流就行了,第二问是求最多去掉几条变仍然能构成最短路,那么此时把边都赋成1,跑一边最短路,用总边数一减就ok了,
需要补充的一点是,两个add函数如果同名,变量的数目不一样不发生冲突,因为这是重载
代码如下:
#include <iostream>
#include <vector>
#include <string.h>
#include <stdio.h>
#include <queue>
using namespace std;
const int maxn=2005;
const int INF=0x3f3f3f3f;
struct Edge
{
int v;
int cost;
Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {}
};
vector <Edge>E[maxn];
void add(int u,int v,int w)
{
E[u].push_back(Edge(v,w));
}
bool vis [maxn];
int cnt[maxn];
int dist [maxn];
bool spfa(int start,int n)
{
memset(vis,false,sizeof(vis));
for(int i=1; i<=n; i++)
dist[i]=INF;
vis[start]=true;
dist[start]=0;
queue<int>que;
while(!que.empty())
que.pop();
que.push(start);
memset(cnt,0,sizeof(cnt));
cnt[start]=1;
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=false;
for(int i=0;i<E[u].size();i++)
{
int v=E[u][i].v;
if(dist[v]>dist[u]+E[u][i].cost)
{
dist[v]=dist[u]+E[u][i].cost;
if(!vis[v])
{
vis[v]=true;
que.push(v);
if(++cnt[v]>n)
return false;
}
}
}
}
return true;
}
/
const int oo=1e9;
const int mm=121111;
const int mn=2999;
int node,src,dest,edge;
int ver[mm],flow[mm],_next[mm];
int head[mn],work[mn],dis[mn],q[mn];
void prepare(int _node,int _src ,int _dest)
{
node=_node,src=_src,dest=_dest;
for(int i=0;i<node;++i)
head[i]=-1;
edge=0;
}
void addedge(int u,int v,int c)
{
ver[edge]=v,flow[edge]=c,_next[edge]=head[u],head[u]=edge++;
ver[edge]=u,flow[edge]=0,_next[edge]=head[v],head[v]=edge++;
}
bool Dicnic_bfs()
{
int i,u,v,l,r=0;
for(i=0;i<node;++i)
dis[i]=-1;
dis[q[r++]=src]=0;
for(l=0;l<r;++l)
for(i=head[u=q[l]];i>=0;i=_next[i])
if(flow[i]&&dis[v=ver[i]]<0)
{
dis[q[r++]=v]=dis[u]+1;
if(v==dest)
return 1;
}
return 0;
}
int Dicnic_dfs(int u,int exp)
{
if(u==dest)
return exp;
for(int &i=work[u],v,tmp;i>=0;i=_next[i])
if(flow[i]&&dis[v=ver[i]]==dis[u]+1&&(tmp=Dicnic_dfs(v,min(exp,flow[i])))>0)
{
flow[i]-=tmp;
flow[i^1]+=tmp;
return tmp;
}
return 0;
}
int Dicnic_flow()
{
int i,ret=0,delta;
while(Dicnic_bfs())
{
for(i=0;i<node;++i)
work[i]=head[i];
while(delta=Dicnic_dfs(src,oo))
ret+=delta;
}
return ret;
}
int u[60005],v[60005],w[60005];
int b[mn][2],dist2[mn];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<=n;i++)
E[i].clear();
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
add(u[i],v[i],w[i]);
add(v[i],u[i],w[i]);
}
spfa(1,n);
memcpy(dist2,dist,sizeof(dist));
//memset(dist,0,sizeof(dist));
spfa(n,n);
int k=0;
for(int i=0;i<m;i++)
{
if(dist2[u[i]]>dist2[v[i]])
swap(u[i],v[i]);
if(dist[v[i]]+w[i]+dist2[u[i]]==dist2[n])
{
b[k][1]=u[i];
b[k][0]=v[i];
k++;
}
}
prepare(n+1,1,n);
for(int i=0;i<k;i++)
{
addedge(b[i][1],b[i][0],1);
}
int sum=Dicnic_flow();
for(int i=0;i<n;i++)
E[i].clear();
for(int i=0;i<k;i++)
{
add(b[i][1],b[i][0],1);
add(b[i][0],b[i][1],1);
}
spfa(1,n);
printf("%d %d\n",sum,m-dist[n]);
}
return 0;
}
第二遍写这个题,费死劲了,还是知识掌握的不牢,代码能力太差,这次用的是迪杰斯特拉的模板,感觉还可以
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
const int oo=1e9;
/**oo 表示无穷大*/
const int maxm=200005;
/**maxm 表示边的最大数量,记住要是原图的两倍,在加边的时候都是双向的*/
const int maxn=2999;
/**maxn 表示点的最大数量*/
int node,src,dest,edge;
/**node 表示节点数,src 表示源点,dest 表示汇点,edge 统计边数*/
int ver[maxm],flow[maxm],_next[maxm];
/**ver 边指向的节点,flow 边的容量 ,_next 链表的下一条边*/
int head[maxn],work[maxn],dis[maxn],q[maxn];
void prepare(int _node,int _src ,int _dest)
{
node=_node,src=_src,dest=_dest;
for(int i=0;i<node;++i)
head[i]=-1;
edge=0;
}
void addedge(int u,int v,int c)
{
ver[edge]=v,flow[edge]=c,_next[edge]=head[u],head[u]=edge++;
ver[edge]=u,flow[edge]=0,_next[edge]=head[v],head[v]=edge++;
}
bool Dicnic_bfs()
{
int i,u,v,l,r=0;
for(i=0;i<node;++i)
dis[i]=-1;
dis[q[r++]=src]=0;
for(l=0;l<r;++l)
for(i=head[u=q[l]];i>=0;i=_next[i])
if(flow[i]&&dis[v=ver[i]]<0)
{
dis[q[r++]=v]=dis[u]+1;
if(v==dest)
return 1;
}
return 0;
}
int Dicnic_dfs(int u,int exp)
{
if(u==dest)
return exp;
for(int &i=work[u],v,tmp;i>=0;i=_next[i])
if(flow[i]&&dis[v=ver[i]]==dis[u]+1&&(tmp=Dicnic_dfs(v,min(exp,flow[i])))>0)
{
flow[i]-=tmp;
flow[i^1]+=tmp;
return tmp;
}
return 0;
}
int Dicnic_flow()
{
int i,ret=0,delta;
while(Dicnic_bfs())
{
for(i=0;i<node;++i)
work[i]=head[i];
while(delta=Dicnic_dfs(src,oo))
ret+=delta;
}
return ret;
}
//
struct Edge
{
int to,next,w;
} edges[maxm];
int tot;
int head2[maxn];
void init()
{
tot = 0;
memset(head2,-1,sizeof(head2));
}
void add(int u,int v,int w)
{
edges[tot].to=v;
edges[tot].w=w;
edges[tot].next=head2[u];
head2[u]=tot++;
// cout<<head2[u]<<endl;
}
bool vis[maxn];
struct sa
{
int u,w;
sa(int u,int d):u(u),w(d) {}
};
bool operator < (sa a,sa b)
{
return a.w > b.w;
}
void dijk(int s,int n)
{
memset(vis,0,sizeof(vis));
priority_queue<sa> que;
for(int i=0; i<=n; i++) dis[i]=oo;
dis[s]=0;
que.push(sa(s,0));
while(!que.empty())
{
sa tmp = que.top();
que.pop();
int u=tmp.u;
if(vis[u]) continue;
vis[u]=true;
for(int e=head2[u]; e!=-1; e=edges[e].next)
{
int v=edges[e].to,w=edges[e].w;
if(vis[v]) continue;
if(dis[u]+w<dis[v])
{
dis[v]=dis[u]+w;
que.push(sa(v,dis[v]));
}
}
}
}
int u[60006],v[60006],w[60006];
int b[maxn][2],dis2[maxn];
int main()
{
int n,m;
while(cin>>n>>m)
{
init();
memset(u,0,sizeof(u));
memset(v,0,sizeof(v));
memset(w,0,sizeof(w));
for(int i=0;i<m;i++)
{
cin>>u[i]>>v[i]>>w[i];
add(u[i],v[i],w[i]);
add(v[i],u[i],w[i]);
}
dijk(1,n);
for(int i=0;i<=n;i++)
dis2[i]=dis[i];
memset(dis,0,sizeof(dis));
dijk(n,n);
int k=0;
for(int i=0;i<m;i++)
{
//我觉得这个地方一定要注意一下,一定要把起点和终点的顺序弄对,
//如果两个距离反了,交换的应该是两个点而不是距离
if(dis2[u[i]]>dis2[v[i]])
swap(u[i],v[i]);
if(dis[v[i]]+w[i]+dis2[u[i]]==dis[1])
{
b[k][1]=u[i];
b[k][0]=v[i];
k++;
}
}
prepare(n+1,1,n);
for(int i=0;i<k;i++)
{
addedge(b[i][1],b[i][0],1);
}
int sum=Dicnic_flow();
memset(dis,0,sizeof(dis));
for(int i=0;i<k;i++)
{
add(b[i][1],b[i][0],1);
// add(b[i][0],b[i][1],1);
}
dijk(1,n);
cout<<sum<<" "<<m-dis[n]<<endl;
}
return 0;
}