acm寒假集训第七讲总结

1.Stockbroker Grapevine

思路:
使用一个邻接矩阵储存图,再使用floyd算法找出每个节点到任一其他节点的时间,每个人的用时即为传递到最远的人的耗时,再找出耗时最短的人即可,通过查询是否有节点断开判断连通性

代码:

#include <bits/stdc++.h>
using namespace std;
int am[105][105];
void floyd(int n)
{
	for(int k=1;k<=n;k++)
	{
		for(int x=1;x<=n;x++)
		{
			for(int y=1;y<=n;y++)
			{
				if(am[x][k]!=INT_MAX&&am[k][y]!=INT_MAX)
				{
					am[x][y]=min(am[x][y],am[x][k]+am[k][y]);
				}
			}
		}
	}
}
int concact(int n)
{
	int i,x,y,is=0,panduan=1;
	for(i=1;i<=n;i++)
	{
		is=0;
		for(x=1;x<=n;x++)
		{
			if(x==i)
			{
				continue;
			}
			if(am[x][i]==INT_MAX)
			{
				is++;
			}
		}
		for(y=1;y<=n;y++)
		{
			if(y==i)
			{
				continue;
			}
			if(am[i][y]==INT_MAX)
			{
				is++;
			}
		}
		if(is==2*n-2)
		{
			panduan=0;
		}
	}
	return panduan;
}
int main() 
{
    int n;
    cin>>n;
    while(n!=0)
    {
    	int i,j;
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=n;j++)
    		{
    			am[i][j]=INT_MAX;
			}
		}
    	for(i=1;i<=n;i++)
    	{
    		int aim,d,num;
    		cin>>num;
    		for(j=0;j<num;j++)
    		{
    			cin>>aim>>d;
    			am[i][aim]=d;
			}
			am[i][i]=0;
		}
		floyd(n);
		if(concact(n)==0)
		{
			cout<<"disjoint"<<endl;
			cin>>n;
			continue;
		}
		int time[n+1];
		for(i=1;i<=n;i++)
		{
			time[i]=INT_MIN;
		}
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=n;j++)
			{
				if(i==j)
				{
					continue;
				}
				if(am[i][j]>time[i])
				{
					time[i]=am[i][j];
				}
			}
		}
		int min=INT_MAX,p=0;
		for(i=1;i<=n;i++)
		{
			if(time[i]<min)
			{
				min=time[i];
				p=i;
			}
		}
		cout<<p<<" "<<min<<endl;
		cin>>n;
	}
    return 0;
}

2.树的直径

思路:
使用邻接表储存,用两遍Dijkstra算法找出直径,第一遍从任一点到最远点A,第二遍从A到最远点B即为直径

代码:

#include <bits/stdc++.h>
using namespace std;
vector<int> tree[100005];
pair<int,int> dfs(int now,int parent)
{
	pair<int,int> max_dot={0,now};
	int i=0;
	for(i=0;i<tree[now].size();i++)
	{
		if(tree[now][i]!=parent)
		{
			pair<int,int> a=dfs(tree[now][i],now);
			a.first++;
			max_dot=max(max_dot,a);
		}
	}
	return max_dot;
}
int main()
{
	int n,i;
	cin>>n; 
	for(i=0;i<n-1;i++)
	{
		int u,v;
		cin>>u>>v;
		tree[u].push_back(v);
		tree[v].push_back(u);
	}
	pair<int,int> d1=dfs(1,-1);
	pair<int,int> d2=dfs(d1.second,-1);
	cout<<d2.first;
	return 0;
}

3.Invitation Cards

思路:
使用邻接表储存,再创建一张反向的邻接表计算回程,使用Dijkstra算法,将出发点到其他节点的距离都记录在dis数组中,再求和
代码:

#include <iostream>
#include <vector>
#include <queue>
#include <functional>
#include <cstring>
using namespace std;
const int MAXN=1000001;
long long int dis[MAXN];
bool vis[MAXN];
vector<pair<int,int>> graph[MAXN];
vector<pair<int,int>> reverse_graph[MAXN];
void Dijkstra(int start,vector<pair<int, int>> adj[]) 
{
    priority_queue<pair<long long int, int>,vector<pair<long long int, int>>, greater<pair<long long int, int>>> pq;
    memset(dis,0x3f,sizeof(dis));
    memset(vis,false,sizeof(vis));
    dis[start]=0;
    pq.push({0,start});
    while(!pq.empty()) 
	{
        int u=pq.top().second;
        pq.pop();
        if(vis[u]) continue;
        vis[u]=true;
        for(auto &edge : adj[u]) 
		{
            int v = edge.first;
            int w = edge.second;
            if (!vis[v] && dis[v] > dis[u] + w) 
			{
                dis[v] = dis[u] + w;
                pq.push({dis[v], v});
            }
        }
    }
}
int main() 
{
    int N;
    cin >> N;
    while (N--) 
	{
        int P, Q;
        cin >> P >> Q;
        for (int i = 1; i <= P; ++i) 
		{
            graph[i].clear();
            reverse_graph[i].clear();
        }
        for (int i = 0; i < Q; ++i) 
		{
            int u, v, w;
            cin >> u >> v >> w;
            graph[u].emplace_back(v, w);
            reverse_graph[v].emplace_back(u, w);
        }
        long long int sum = 0;
        Dijkstra(1, graph);
        for (int i = 2; i <= P; ++i) 
		{
            sum += dis[i];
        }
        Dijkstra(1, reverse_graph);
        for (int i = 2; i <= P; ++i) 
		{
            sum += dis[i];
        }
        cout<<sum<<endl;
    }
    return 0;
}

4.战略游戏

思路:
使用邻接表储存,用动态规划的思路,记录在i点放/不放士兵时的士兵数量为f[i][1/0],转移方程为f[i][0]=f[i+1][1],f[i][1]=min(f[i+1][0],f[i+1][1]),最后输出min(f[0][1],f[0][0])即可
代码:

#include <bits/stdc++.h>
using namespace std; 
vector<int> at[1505];
int f[1505][2];
void dp(int now,int parent)
{
	f[now][0]=0;
	f[now][1]=1;
	for(int i:at[now])
	{
		if(i==parent)
		{
			continue;
		}
		dp(i,now);
		f[now][0]+=f[i][1];
		f[now][1]+=min(f[i][0],f[i][1]); 
	}
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		int k,i_dot;
		cin>>i_dot>>k;
		for(int j=0;j<k;j++)
		{
			int r;
			cin>>r;
			at[i_dot].push_back(r);
			at[r].push_back(i_dot);
		}
	}
	dp(0,-1);
	cout<<min(f[0][1],f[0][0]);
	return 0;
}

学习总结:
通过这次的学习,我学习了图和树的相关知识,通过领接矩阵或者邻接表来储存图和树,还学习了Floyd算法和Dijkstra算法来计算最短路径问题,了解了dfs和bfs也可以用于在图和树中进行查询,还了解了树形DP的基本内容

posted @ 2025-02-19 21:30  asdadsdf  阅读(21)  评论(0)    收藏  举报