题目
这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;
}