天梯赛自主练习3补题 (16年决赛,我要是16年去打决赛就有机会国一了,不过现在22年,不能拿现在的水平和原来比)

题目
这16年的确实简单啊,我都能达到250分了,羡慕16年。

L2-1 红色警报
题意: 给定n个点m条边,依次删除k个点。每删除一个点,根据删除后连通块是否增加决定输出什么,如果所有点都被删除,输出"Game Over".
思路: 我想着是倒着操作,LCT我肯定不会,只能倒着连边。如果某个点连接的两个点不在一棵树上,说明删除该点时二者不连通了。但是wa了一个点,不知道为什么,上完课研究一下。
题解用的方法很暴力,但是确实没问题,而且能保证正确性。没删除一个点重新建并查集,nnn,500^3,确实是个能过的复杂度。
时间复杂度: O(nnn)
代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 502;
#define fir(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;
int n,m,k,T;
int fa[N];
int a[N][N];
int find(int x)
{
	return x==fa[x]?x:fa[x] = find(fa[x]);
}
void Merge(int u,int v)
{
	u = find(u),v = find(v);
	if(u != v)
	{
		fa[v] = u;
	}
}
bool vis[N];
void solve()
{
	cin>>n>>m;
	fir(i,0,n-1) fa[i] = i;
	for(int i=0;i<m;++i)
	{
		int x,y; cin>>x>>y;
		a[x][y] = a[y][x] = 1;
		Merge(x,y);
	}
	int cnt = 0;
	fir(i,0,n-1) if(find(i) == i) cnt++;
	cin>>k;
	for(int t=0;t<k;++t)
	{
		int x; cin>>x;
		vis[x] = 1;
		fir(i,0,n-1) fa[i] = i;
		for(int i=0;i<n;++i)
		{
			for(int j=i+1;j<n;++j)
			{
				if(vis[i] || vis[j] || !a[i][j]) continue;
				Merge(i,j); 
			}
		}
		int sum = 0;
		fir(i,0,n-1) if(!vis[i] && find(i)==i) sum++;
		// cout<<sum<<"?"<<endl;
		if(sum > cnt) printf("Red Alert: City %d is lost!\n",x);
		else printf("City %d is lost.\n",x);
		cnt = sum;
		if(cnt == 0) printf("Game Over.");
  	}
}
signed main(void)
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	solve();
	return 0;
}

L3-2直捣黄龙
题意: 略。求最短路,不唯一选点数最多,若也不唯一选点权和最大。
思路: Dij跑就完事了,不过由于输入是字符串,要用map映射一下,n<=100,带log也没事。条件不唯一的时候少更新了点权和数组,导致wa了一个点。(还乱改代码多骗了5分,因为恰好是点权和最大的路径是最优解)
时间复杂度: O(mlogm + nlogn)
代码:

#include<bits/stdc++.h>
using namespace std;
#define mem(a,x) memset(a,x,sizeof(a))
const int N = 402;
const int M = N*N;
typedef long long ll;
#define int long long
typedef pair<int,int> PII;
int n,m,k,T;
//最短路、点的个数、点权和
int h[N],e[M],ne[M],w[M],idx = 0;
void add(int a,int b,int c)
{
	e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx++;
}
int a[N];
int num[N]; //方案数
int cnt[N]; //点数
int sum[N]; //点权和
int dist[N];
bool vis[N];
map<string,int> to;
int pre[N];
map<int,string> to2;
int tot = 0;
int fun(string s)
{
	int wh;
	if(to[s])
	{
		wh = to[s];
	}
		else
		{
			to[s] = ++tot;
			wh = tot;
		}
    // if(s=="PAT") cout<<s<<":"<<wh<<"?\n";
	to2[wh] = s;
	return wh;
}
void Dij(int S)
{
   mem(dist,0x3f);
   mem(vis,false);
   dist[S] = 0;
   num[S] = 1;
   cnt[S] = 0;
   sum[S] = a[S];
   priority_queue<PII,vector<PII>,greater<PII> > q;
   q.push({0,S});
   while(q.size())
   {
   	  PII tmp = q.top(); q.pop();
   	  int u = tmp.second;
   	  if(dist[u] != tmp.first) continue;
   	  // if(vis[u]) continue;
   	  // vis[u] = 1;
   	  for(int i=h[u];~i;i=ne[i])
   	  {
   	  	 int j = e[i];
   	  	 if(dist[j] > dist[u] + w[i])
   	  	 {
   	  	 	dist[j] = dist[u] + w[i];
   	  	 	pre[j] = u;
   	  	 	num[j] = num[u];
   	  	 	cnt[j] = cnt[u] + 1;
   	  	 	sum[j] = sum[u] + a[j];
   	  	 	q.push({dist[j],j});
   	  	 }
   	  	 else if(dist[j] == dist[u] + w[i])
   	  	 {
   	  	 	 num[j] += num[u];
   	  	 	 if(cnt[j] < cnt[u] + 1)
   	  	 	 {
   	  	 	 	cnt[j] = cnt[u] + 1;
   	  	 	 	sum[j] = sum[u] + a[j];
   	  	 	 	pre[j] = u;
   	  	 	 }
   	  	 	 else if(cnt[j] == cnt[u] + 1)
   	  	 	 {
   	  	 	 	if(sum[j] < sum[u] + a[j])
   	  	 	 	{
   	  	 	 		sum[j] = sum[u] + a[j];
   	  	 	 		pre[j] = u;
   	  	 	 	}
   	  	 	 }
   	  	 }
   	  }
   }	
}
void solve()
{
	mem(h,-1); mem(pre,-1);
	cin>>n>>m;
	string s1,s2;
	cin>>s1>>s2; to[s1] = ++tot,to[s2] = ++tot;
	to2[1] = s1; to2[2] = s2;
	for(int i=0;i<n-1;++i)
	{
		string s; int x; cin>>s>>x;
		int wh = fun(s);
		a[wh] = x;
	}
	while(m--)
	{
		string s1,s2; cin>>s1>>s2; int x; cin>>x;
		int l = fun(s1);
	    int r = fun(s2);
	    add(l,r,x); add(r,l,x);
	}
	Dij(1);
	int now = 2;
	vector<int> va;
	while(now != -1)
	{
		va.push_back(now);
		now = pre[now];
	}
	reverse(va.begin(),va.end());
	for(int i=0;i<va.size();++i)
	{
		if(i) cout<<"->";
		cout<<to2[va[i]];
	}
	cout<<"\n";
	cout<<num[2]<<" "<<dist[2]<<" "<<sum[2];
}
signed main(void)
{
	solve();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值