图论专题测试 【最短路】【网络流】解题报告

xiaoxiao2021-02-28  94

今天进行了一个测试。比上次简单些。。。

第一题

思路

找一个最短路的值,还要记录路径。SPFA再跑一遍找一下还有哪些路径。但是注意,会被卡的!加了优化还是只有60分。所以就看看代码吧。

代码

先是我的:

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<vector> #include<queue> using namespace std; const int N=300+5; const int M=1e5; const int INF=1e5*N; int n,m,ans=1,flag[N],dis[N],pre[N],head[N],num; deque<int> q; struct edge { int u,v,w,next; edge(){next=-1;} }ed[M+5]; void build(int u,int v,int w) { ed[++num].u=u; ed[num].v=v; ed[num].w=w; ed[num].next=head[u]; head[u]=num; } int SPFA(int s,int e) { for (int i=1;i<=n;i++) dis[i]=(i==s)?0:INF,flag[i]=(i==s)?1:0; while(!q.empty())q.pop_front(); q.push_back(s); while(!q.empty()) { int u=q.front();q.pop_front(); flag[u]=0; for (int i=head[u];i!=-1;i=ed[i].next) { int v=ed[i].v; if (dis[v]>dis[u]+ed[i].w) { dis[v]=dis[u]+ed[i].w; pre[v]=i; if (!flag[v]) { flag[v]=1; if (!q.empty()) { if (dis[v]>dis[q.front()])q.push_back(v); else q.push_front(v); } else q.push_back(v); } } } } return dis[e]; } int main() { freopen("change.in","r",stdin); freopen("change.out","w",stdout); memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); build(u,v,w); } int minn=SPFA(1,n); while(true) { for (int u=n;u!=1;u=ed[pre[u]].u) ed[pre[u]].w=INF; int _minn=SPFA(1,n); if (minn==_minn)ans++; else break; } printf("%d",ans); return 0; }

然后:

#include<stdio.h> #include<cstring> #include<algorithm> #include<queue> #include<map> using namespace std; struct edge { int v,last,mrk,u,w; }ed[400010]; priority_queue < pair<int,int> ,vector< pair<int,int> > ,greater<pair<int,int> > > state; int head[100010],se[100010],dis[100010],frm[400010]; int n,m,ans,bns,cns,num=0,INF=1e9+7; void add(int u,int v,int w) { num++; ed[num].v=v; ed[num].w=w; ed[num].u=u; ed[num].mrk=0; ed[num].last=head[u]; head[u]=num; } int spfa(int flag) { memset(frm,0,sizeof(frm)); memset(se,0,sizeof(se)); while(!state.empty()) state.pop(); for(int i=1;i<=n;i++) dis[i]=INF; state.push(make_pair(0,1)); se[1]=1,dis[1]=0; while(!state.empty()) { int u=state.top().second; se[u]=0; state.pop(); for(int i=head[u];i;i=ed[i].last) if(ed[i].mrk==0) { int v=ed[i].v; if(dis[v]>dis[u]+ed[i].w) { dis[v]=dis[u]+ed[i].w; frm[v]=i; if(!se[v]) { state.push(make_pair(dis[v],v)); se[v]=1; } } } } if(flag==0) cns=dis[n]; int p=frm[n]; while(p) { ed[p].mrk=1; p=frm[ed[p].u]; } return dis[n]; } void sov(int flag) { int bns; while(1) { bns=spfa(flag); if(bns!=cns) break ; flag++,ans++; } } int main() { freopen("change.in","r",stdin); freopen("change.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } sov(0); printf("%d",ans); } /* Whoso pulleth out this sword from this stone and anvil is duly born King of all England */

第二题

思路:

网络流。二分等级,把比这个mid小的加上。然后分奇偶(注意特判2)建图,边上记录火力值,然后二分图之间是INF,跑一边最大流最小割就好了。具体看代码。

代码

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<queue> using namespace std; const int INF=0x3f3f3f3f; const int N=5e5+5; struct edge { int v,w,last; }ed[2*N]; int head[N],dis[N],tim[N],pow[N],l[N],primes[4*N],isnot[4*N],x[4*N]; int n,k,num=1,cns,S,T,big=0,ptot=0; int min(int x,int y) { if (x<=y) return x; else return y; } int max(int x,int y) { if (x>=y) return x; else return y; } void build(int u,int v,int w) { num++; ed[num].v=v; ed[num].w=w; ed[num].last=head[u]; head[u]=num; } void getphi(int n) { isnot[1]=1; for (int i=2;i<=n;i++) if (!isnot[i]) { primes[ptot++]=i; for (int j=i+i;j<=n;j+=i) isnot[j]=1; } } int bfs() { queue<int> state; memset(dis,-1,sizeof(dis)); state.push(S); dis[S]=0; while(!state.empty()) { int u=state.front(); state.pop(); for (int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if (dis[v]==-1&&ed[i].w>0) { dis[v]=dis[u]+1; state.push(v); } } } if (dis[T]==-1) return 0; return 1; } int dfs(int u,int low) { int a=0; if (u==T) return low; for (int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if (ed[i].w>0&&dis[v]==dis[u]+1) { int tmp=dfs(v,min(low-a,ed[i].w)); ed[i].w-=tmp,ed[i^1].w+=tmp; a+=tmp; } } return a; } int main() { freopen("card.in","r",stdin); freopen("card.out","w",stdout); getphi(1000005); scanf("%d%d",&n,&k); for (int i=1;i<=n;i++) { scanf("%d%d%d",&pow[i],&tim[i],&l[i]); big=max(big,l[i]); } int lf=1,rg=1e9+7,ans=-1; while(lf<=rg) { memset(head,0,sizeof(head)); memset(x,0,sizeof(x)); int mid=(lf+rg)>>1,big=0,tar,t=0,tot=0; num=1,cns=0; for (int i=1;i<=n;i++) if (l[i]<=mid&&pow[i]>big&&tim[i]==1) big=pow[i],tar=i; for (int i=1;i<=n;i++) if (l[i]<=mid&&(i==tar||tim[i]>1)) { x[++t]=i; tot+=pow[i]; } S=0,T=t+2;//建立汇点源点 for (int i=1;i<=t;i++) if (tim[x[i]]&1) { build(S,i,pow[x[i]]); build(i,S,0); }//奇数建边 else { build(i,T,pow[x[i]]); build(T,i,0); }//偶数建边 for (int i=1;i<=t;i++) if (tim[x[i]]&1) for (int j=1;j<=t;j++) if ((~tim[x[j]]&1)&&!isnot[tim[x[i]]+tim[x[j]]]) { build(i,j,INF); build(j,i,0); }//特判 while(bfs()) { int bns=0; while(bns=dfs(S,INF)) tot-=bns; } if (tot>=k) rg=(ans=mid)-1; else lf=mid+1; } printf("%d",ans); return 0; }

第三题

思路

SPFA找最短路。一样要优化!分成两种,一种是灵力,一种是时间。用tarjan找强连通分量(因为只有这样会产生“眩晕”),再最短路。 刚开始找强连通分量用的是SPFA。。。又被卡了。。。

代码

#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cmath> using namespace std; const int N=1e5+5; int n,m,head[N],num,dfn[N],low[N],con[N],sta[N],flag[N],top,tim; long long dis[N]; long long cost[N]; struct edge { int v,w; int next; edge(){next=-1;} }ed[N+5]; void build(int u,int v,int w) { ed[++num].v=v; ed[num].w=w; ed[num].next=head[u]; head[u]=num; } void tarjan(int u) { dfn[u]=low[u]=++tim; flag[sta[++top]=u]=1; for (int i=head[u];i!=-1;i=ed[i].next) { int v=ed[i].v; if (!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if (flag[v])low[u]=min(low[u],dfn[v]); } if (dfn[u]==low[u]) for (int now=0;now!= u;) { flag[now=sta[top--]]=0; con[now]=u; } } void SPFA() { deque<int> q; memset(flag,0,sizeof flag); memset(dis,-1,sizeof dis); memset(cost,-1,sizeof cost); q.push_back(1);dis[1]=0,cost[1]=0; while(!q.empty()) { int u=q.front(); q.pop_front(); flag[u]=0; for (int i=head[u];i!=-1;i=ed[i].next) { int v=ed[i].v; int cc=con[v]==con[u]?cost[u]+1:cost[u]; if (cost[v]>cc||cost[v]==-1||(dis[v]>dis[u]+ed[i].w&&cost[v]==cc)||(dis[v]==-1&&cost[v]==cc)) { cost[v]=cc; dis[v]=dis[u]+ed[i].w; if (!flag[v]) { flag[v]=1; if (!q.empty()) { if (dis[v]>dis[q.front()])q.push_back(v); else q.push_front(v); } q.push_back(v); } } } } } int main() { freopen("festival.in","r",stdin); freopen("festival.out","w",stdout); memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); build(v,u,w); } for (int i=1;i<=n;i++) if (!con[i])tarjan(i); SPFA(); for (int k=2;k<=n;k++) { if (dis[k]==dis[0]) printf("-1\n"); else printf("%I64d %I64d\n",cost[k],dis[k]); } return 0; }

以上

转载请注明原文地址: https://www.6miu.com/read-80825.html

最新回复(0)