20170824图论选讲部分习题
Posted dancer16
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20170824图论选讲部分习题相关的知识,希望对你有一定的参考价值。
1.车站分级
讲过啊,拓扑排序,每个停靠的车站向所有未停靠的车站连一条边,拓扑层数即可,小优化,每次删0度点的边时顺便统计一下删好后为0度点的边
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define maxn 1005 using namespace std; int to[maxn][maxn],point[maxn],Map[maxn][maxn],x[maxn],v[maxn],a[maxn],b[maxn]; int ans=0,n,m; void work() { for(int i=1;i<=n;i++) if(!v[i]) point[++point[0]]=i; while(point[0]) { ans++; while(point[0]) { int k=point[point[0]];point[0]--; for(int i=1;i<=to[k][0];i++) { v[to[k][i]]--; if(!v[to[k][i]]) x[++x[0]]=to[k][i]; } } for(int i=1;i<=x[0];i++) point[i]=x[i]; point[0]=x[0]; x[0]=0; } printf("%d\n",ans); } int main() { scanf("%d %d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d",&a[0]); b[0]=0; for(int i=1;i<=a[0];i++) scanf("%d",&a[i]); for(int i=1;i<a[0];i++) for(int j=a[i]+1;j<a[i+1];j++) b[++b[0]]=j; for(int i=1;i<=a[0];i++) for(int j=1;j<=b[0];j++) if(!Map[a[i]][b[j]]) { Map[a[i]][b[j]]=1; v[b[j]]++; to[a[i]][++to[a[i]][0]]=b[j]; } } work(); }
2.种树,这个我写过题解了
3.秦始皇的国家道路。先枚举选的是那条边,因为cnt总值最小肯定更优,我们用Prim求最小生成树可以接近最优值,考虑到加上选的边后的最小生成树是由原最小生成树换1条边的正确性可由Kruskal来证明吧。就是把最小生成树中u,v中的那条路径中最大的一条边换成枚举的那条边。
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; struct node{ int x,y; double val; }a[2000005]; int num1,num,f1,root; int f[2000005],p[2000005],flag[2000005]; double dis[1005][1005],x[2000005],y[2000005]; int v[2000005],next[2000005],head[10005],vis[10005]; double v1[2000005]; int find(int u) { if (f[u]!=u) f[u]=find(f[u]); return f[u]; } void add(int a,int b,double val) { num1++; v[num1]=b; v1[num1]=val; next[num1]=head[a]; head[a]=num1; } bool cmp(node a,node b) { return a.val<b.val; } void dfs(int u,double val) { dis[root][u]=val; vis[u]=f1; for (int i=head[u]; i; i=next[i]) { int V=v[i]; if (vis[V]!=f1) dfs(V,max(val,v1[i])); } } int main() { int asdasdasdasd; int t; scanf("%d",&t); while (t--) { num1=0; num=0; int n; scanf("%d",&n); for (int i=1; i<=n; i++) head[i]=0; for (int i=1; i<=n; i++) scanf("%lf%lf%d",&x[i],&y[i],&p[i]); for (int i=1; i<=n; i++) for (int j=i+1; j<=n; j++) { double dis=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); num++; a[num].x=i; a[num].y=j; a[num].val=sqrt(dis); /*num++; a[num].x=j; a[num].y=i; a[num].val=sqrt(dis);*/ } sort(a+1,a+num+1,cmp); for (int i=1; i<=n; i++) f[i]=i; double ans=0; for (int i=1; i<=num; i++) { flag[i]=0; int fx=find(a[i].x); int fy=find(a[i].y); if (fx!=fy) { f[fx]=fy; //f[fx]=find(fx); ans+=a[i].val; flag[i]=1; } } for (int i=1; i<=num; i++) if (flag[i]) { add(a[i].x,a[i].y,a[i].val); add(a[i].y,a[i].x,a[i].val); } f1=0; for (int i=1; i<=n; i++) { f1++; root=i; dfs(i,0); } double ans1=0; for (int i=1; i<=n; i++) for (int j=i+1; j<=n; j++) if ((p[i]+p[j])/(ans-dis[i][j])>ans1) ans1=(p[i]+p[j])/(ans-dis[i][j]); printf("%.2f\n",ans1); } return 0; }
4.受欢迎的奶牛
Tarjan求强连通分量缩点
求度为0的个数,如果大于等于2个,无解,不然输出度为0的强连通分量的size
#include<iostream> #include<cstdio> #include<algorithm> #include<stack> #define maxn 100100 using namespace std; stack<int> S; struct note{ int u,v; }edge[maxn]; bool instack[maxn]; int to[maxn*2],id[maxn],Time,ans,num,sc,head[maxn],visit[maxn],next[maxn*2],low[maxn],dfn[maxn],n,m,size[maxn]; void make_way(int u,int v) { to[++num]=v; next[num]=head[u]; head[u]=num; } void tarjan(int u,int fa) { dfn[u]=low[u]=++Time; instack[u]=1; S.push(u); for(int ed=head[u];ed;ed=next[ed]) { if(!dfn[to[ed]]) { tarjan(to[ed],u); low[u]=min(low[u],low[to[ed]]); }else if(instack[to[ed]]) low[u]=min(low[u],dfn[to[ed]]); } //cout<<u<<‘ ‘<<low[u]<<‘ ‘<<dfn[u]<<endl; if(low[u]==dfn[u]) { sc++; int v; do{ v=S.top(); S.pop(); instack[v]=0; id[v]=sc; size[sc]++; }while(v!=u&&!S.empty()); } } int main() { scanf("%d %d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d %d",&edge[i].u,&edge[i].v); make_way(edge[i].u,edge[i].v); } for(int i=1;i<=n;i++) if(!dfn[i]) { tarjan(i,0); } for(int i=1;i<=m;i++) if(id[edge[i].u]!=id[edge[i].v]) visit[id[edge[i].u]]++; bool flag=0; for(int i=1;i<=sc;i++) { if(!visit[i]) { if(flag) { cout<<0<<endl; return 0; } flag=1; ans=i; } } printf("%d\n",size[ans]); }
6.矿场搭建
WA10分,待改
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define ll long long using namespace std; int n,m,cnt,num,tot,son_num,ans1,Time,T,cases,root; ll ans2; int head[500005],dfn[500500],low[500005],vis[500005]; bool cut[500005]; int Next[1000005],to[1000005]; void make_way(int u,int v) { to[++num]=v; Next[num]=head[u]; head[u]=num; } void tarjan(int u,int fa_edge) { low[u]=dfn[u]=++Time; for(int edge=head[u];edge;edge=Next[edge]) if(edge^1!=fa_edge) { int v=to[edge]; if(!dfn[v]) { tarjan(v,u); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]) { if(u==root) son_num++;else cut[u]=1; } }else { low[u]=min(low[u],dfn[v]); } } } void dfs(int u) { vis[u]=T; if(cut[u]) return; cnt++; for(int edge=head[u];edge;edge=Next[edge]) { if(cut[to[edge]]&&vis[to[edge]]!=T) num++,vis[to[edge]]=T; if(!vis[to[edge]]) dfs(to[edge]); } } int main() { int Case=0; while(~scanf("%d",&m)&&m) { Case++; memset(head,0,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(vis,0,sizeof(vis)); memset(low,0,sizeof(low)); memset(cut,0,sizeof(cut)); Time=num=n=ans1=T=0; for(int i=1;i<=m;i++) { int u,v; scanf("%d %d",&u,&v); n=max(n,max(u,v)); make_way(u,v); make_way(v,u); } for(int i=1;i<=n;i++) { if(!dfn[i])tarjan(root=i,0); if(son_num>=2) cut[root]=1; son_num=0; } ans1=0; ans2=1; for(int i=1;i<=n;i++) if(!vis[i]&&!cut[i]) { T++;cnt=num=0; dfs(i); if(!num) ans1+=2,ans2*=cnt*(cnt-1)/2; if(num==1) ans1++,ans2*=cnt; } printf("Case %d: %d %lld\n",Case,ans1,ans2); } }
以上是关于20170824图论选讲部分习题的主要内容,如果未能解决你的问题,请参考以下文章