zoukankan      html  css  js  c++  java
  • 洛谷P1197星球大战-链式前向星及其简单运用

    前向星

    在了解链式前向星之前,先简单了解下前向星。前向星是一种边集数组,先把每条边按照从小到大的顺序排序,如果起点一样,那么就按照终点从小到大来排序,并记录下每个点为起点在数组中的位置和该点所连边的数量。

    • (len[i])表示以(i)为起点的边的条数,hehiad[i]表示以(i)为起点的边在数组中存储的第一个位置
    • head[1]=1,len[1]=3
    • head[2]=4,len[2]=1
    • head[3]=5,len[3]=1
    • head[4]=6,len[4]=2

    利用前向星,可以在(O(nlog_2{n}))时间内排序+处理,(O(1))时间内查询

    前向星特别适合优化SPFA,DFS和BFS

    链式前向星

    使用结构体,添加了当前边指向的下一条边的地址,head数组存放以i为起点的边的地址,next存放下一条边的地址,当next=0时表示最后一条边。

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 100501
    struct NODE{
    	int w;
    	int e;
    	int next; //next[i]表示与第i条边同起点的上一条边的储存位置
    }edge[MAXN];
    int cnt;
    int head[MAXN]; 
    void add(int u,int v,int w){
    	edge[cnt].w=w;
    	edge[cnt].e=v;    //edge[i]表示第i条边的终点 
    	edge[cnt].next=head[u]; //head[i]表示以i为起点的最后一条边的储存位置 
    	head[u]=cnt++;
    }
    int main(){
    	memset(head,0,sizeof(head));
    	cnt=1;
    	int n;
    	cin>>n;
    	int a,b,c;
    	while(n--){
    		cin>>a>>b>>c;
    		add(a,b,c);
    	}
    	int start;
    	cin>>start;
    	for(int i=head[start];i!=0;i=edge[i].next)
    	   cout<<start<<"->"<<edge[i].e<<" "<<edge[i].w<<endl;
    	return 0;
    }
    

    洛谷P1197 星球大战

    基本思路

    使用反并查集,使用链式前向星存储边的状况,vis表示是否被摧毁,由最后时刻反向重建,使用并查集检查联通块数目

    #include<bits/stdc++.h>
    #define FOR(i,a,b) for(int i=a;i<b;i++)
    #define FOR2(i,a,b) for(int i=a;i<=b;i++)
    #define sync ios::sync_with_stdio(false);
    #define ll long long
    #define INF  0x7f7f7f7f;
    #define MAXN 500010
    #define ok1 cout<<"OK1"<<endl
    #define ok2 cout<<"OK2"<<endl
    #define ok3 cout<<"OK3"<<endl
    #define MOD 10007
    using namespace std;
    int f[MAXN],store[MAXN],ans[MAXN];
    int cnt=0;bool vis[MAXN];	int h[MAXN];
    typedef struct{
    	int w,from,to,next;
    }EDGE; EDGE edges[MAXN];
    void add(int u,int v)
    {//链式前向星 
    	edges[cnt].from=u;
    	edges[cnt].to=v;
    	edges[cnt].next=h[u];
    	h[u]=cnt++;
    }
    int find(int x)
    {//路径压缩 
    	if(f[x]!=x) f[x]=find(f[x]);
    	return f[x];
    }
    int main()
    {
    	int n,m,a,b,k,x;
    	cin>>n>>m;
    
    	fill(h,h+MAXN,-1);
    	memset(vis,false,sizeof(vis));
    	FOR(i,0,n)
    	{
    		f[i]=i;
    	} 
    	FOR(i,0,m)
    	{
    		cin>>a>>b;
    		add(a,b);add(b,a);//无向图 
    	}
    	cin>>k;
    	int total=n-k;
    	FOR(i,0,k)
    	{
    		cin>>x;
    		store[i]=x;
    		vis[x]=true;//全部毁灭 
    	}
    	FOR(i,0,2*m)
    	{
    		if(vis[edges[i].from]==false&&vis[edges[i].to]==false)
    		{//不是被毁灭的点 
    			int fa=find(edges[i].from);
    			int fb=find(edges[i].to);
    			if(fa!=fb)
    			{
    				f[fa]=fb;
    				total--;//计算联通块,若能本来不联通,联通块数目-- ,本来联通则不变 
    			}
    		}
    	}
    	ans[k]=total; //倒着重建
    	for(int i=k-1;i>=0;i--) 
    	{
    		int u=store[i];
    		total++;
    		vis[u]=false;
    		for(int j=h[u];j!=-1;j=edges[j].next)
    		{
    			if(vis[edges[j].to]==false){
    				int fa=find(edges[j].from);
    				int fb=find(edges[j].to);
    				if(fa!=fb){
    					f[fa]=fb;
    					total--;//本来不连通,重建后联通 ,本来联通就不变 
    				} 
    			} 
    		}
    		ans[i]=total;
    	} 
    	FOR2(i,0,k) 
    		cout<<ans[i]<<endl; 
    	return 0;
    }
    
  • 相关阅读:
    #Flag QBXT学习计划
    #蓝书整理 补充推导 [ 流水作业调度问题 ]
    #luogu整理 种树
    #loj整理 活动安排
    #YBT整理 排序算法的例题
    #YBT整理 排序算法
    CYC很好
    #YBT整理 高精度害死人
    #蓝书整理 流水作业调度问题
    #Flag 年前寒假计划
  • 原文地址:https://www.cnblogs.com/tldr/p/11284891.html
Copyright © 2011-2022 走看看