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的基本内容
浙公网安备 33010602011771号