重量不同的硬币
题目描述
Fj有N个硬币,编号为1…N。
现在有W个推断,为(A,B),表示硬币A比硬币B重。
寻找并输出一个硬币编号,要求其重量明确不同于其他硬币的个数最多。
如果有多个答案,输出字典序最小的一个。
如果给出的数据有矛盾,输出"IMPOSSIBLE"
输入格式
Line 1: 两个整数: N and W.
Lines 2…W+1: 每行两个整数: A, B
输出格式
Line 1: 重量不同于其他硬币的个数最多的硬币编号。
样例数据
input
7 6
1 6
1 5
3 6
4 3
2 4
2 5
output
2
首先,我们知道,如果重量的关系出现了矛盾,一定出现了环,我们可以选择用拓扑排序进行判环:
拓扑排序中的点,要想进入拓扑序列,入度必然为0;但是有环,入度必然不为0.因此,我们统计拓扑排序有多少个点进入拓扑序列,如果有点数sum<n,那么就输出Inpossible。
对于统计大小,我们进行dfs遍历,用cnt[]表示连向这个点的关系,注意每一次的初始化要为1,否则无法进行大小统计。再在反图上做一遍DFS即可。
#include<bits/stdc++.h> using namespace std; #define maxn 1200 int n,w; int ans=0,d=0; int q[maxn]={}; int v[maxn]={}; int V[maxn]={}; int In[maxn]={}; int cnt[maxn]={}; int CNT[maxn]={}; vector <int> a[maxn]; vector <int> A[maxn]; inline void read(int &readnum) { int s=0,w=1;char c=getchar(); while (c<'0' || c>'9') {if (c=='-') w=-1; c=getchar();} while (c>='0' && c<='9') s=s*10+c-48,c=getchar(); readnum=s*w;return; } inline int Topsort(void) { int sum=0; int h=1,t=0; for (int i=1;i<=n;++i) if (!In[i]) q[++t]=i; for (;h<=t;++h) { int p=q[h];sum++; for (int i=0;i<a[p].size();++i) { int np=a[p][i]; In[np]--; if (!In[np]) q[++t]=np; } } return sum; } void dfs(int x) { int sum=0; cnt[x]=1,v[x]=1; for (int i=0;i<a[x].size();++i) { int np=a[x][i]; if (v[np]) continue; dfs(np); sum+=cnt[np]; } cnt[x]+=sum; } void DFS(int X) { int SUM=0; CNT[X]=1,V[X]=1; for (int I=0;I<A[X].size();++I) { int NP=A[X][I]; if (V[NP]) continue; DFS(NP); SUM+=CNT[NP]; } CNT[X]+=SUM; } int main() { freopen("coin.in","r",stdin); freopen("coin.out","w",stdout); read(n),read(w); for (int i=0;i<maxn-10;++i) a[i].clear(); for (int i=0;i<maxn-10;++i) a[i].clear(); for (int i=1;i<=w;++i) { int x,y; read(x),read(y); In[y]++; a[x].push_back(y); A[y].push_back(x); } int stp=Topsort(); if (stp<n) { cout<<"IMPOSSIBLE\n"; return 0; } for (int i=1;i<=n;++i) { memset(v,0,sizeof(v)); memset(V,0,sizeof(V)); dfs(i),DFS(i); int tmp=cnt[i]+CNT[i]; if (tmp>ans) ans=tmp,d=i; } cout<<d<<endl; fclose(stdin); fclose(stdin); return 0; }
超级牛游戏
题目描述
现在有N(1 <= N <= 2000)头奶牛在玩 超级牛 游戏。每头奶牛有一个唯一的ID,ID范围是 1 … 2 ^ 30-1。
超级牛比赛是淘汰赛 - 每场比赛后,输者退赛,赢者继续留在比赛,直到只剩一队游戏结束。 输赢是FJ自己决定的,或者说结果可以任意决定!
比赛的积分规则十分奇葩:积分=第一队的ID XOR 第二队的ID。 比如,12队和20队打比赛,积分是24,因为01100 XOR 10100 = 11000。
FJ认为,分越高越刺激。所以他想让总积分最高。请帮助FJ设计比赛。
输入格式
第一行包含一个整数N
以下N行包含N个队伍的ID。
输出格式
一行,一个整数,表示答案。
样例数据
input
4
3
6
9
10
output
37
做法:亮亮连边,组成一个完全图,跑一遍最大生成树(或者发把左右边转成负数跑一遍最小生成树)即可。
#include<bits/stdc++.h> using namespace std; #define LL long long struct edge { int x,y,v; }e[5000000]={}; LL sum=0; int tot=0,n; int fa[2200]={}; int Id[2200]={}; inline void read(int &readnum) { int s=0,w=1;char c=getchar(); while (c<'0' || c>'9') {if (c=='-') w=-1;c=getchar();} while (c>='0' && c<='9') s=s*10+c-48,c=getchar(); readnum=s*w; } inline int get(int x) { if (fa[x]==x) return x; return fa[x]=get(fa[x]); } inline bool cmp(edge a,edge b) { return a.v<b.v; } int main() { freopen("superbull.in","r",stdin); freopen("superbull.out","w",stdout); read(n); for (int i=1;i<=n;++i) fa[i]=i; for (int i=1;i<=n;++i) read(Id[i]); for (int i=1;i<=n;++i) for (int j=i+1;j<=n;++j) e[++tot]=edge{i,j,-(Id[i]^Id[j])}, e[++tot]=edge{j,i,-(Id[j]^Id[i])}; sort(e+1,e+tot+1,cmp); for (int i=1;i<=tot;++i) { int fa1=get(e[i].x); int fa2=get(e[i].y); if (fa1==fa2) continue; fa[fa1]=fa2; sum+=(LL)e[i].v; } cout<<-sum<<endl; fclose(stdin); fclose(stdout); return 0; }
damage
题目描述
农夫John的农场遭受了一场地震.有一些牛棚遭到了损坏,但幸运地,所有牛棚间的路经都还能使用.
FJ的农场有P(1 <= P <= 30,000)个牛棚,编号1…P. C(1 <= C <= 100,000)条双向路经联 接这些牛棚,编号为1…C. 路经i连接牛棚a_i和b_i (1 <= a_i<= P;1 <= b_i <= P).路经 可能连接a_i到它自己,两个牛棚之间可能有多条路经.农庄在编号为1的牛棚.
N (1 <= N <= P)头在不同牛棚的牛通过手机短信report_j(2 <= report_j <= P)告诉FJ它 们的牛棚(report_j)没有损坏,但是它们无法通过路径和没有损坏的牛棚回到到农场.
当FJ接到所有短信之后,找出最小的不可能回到农庄的牛棚数目.这个数目包括损坏的牛棚.
输入格式
第1行: 三个空格分开的数: P, C, 和 N
第2…C+1行: 每行两个空格分开的数: a_i 和 b_i
第C+2…C+N+1行: 每行一个数: report_j
输出格式
第1行: 一个数,最少不能回到农庄的牛的数目(包括损坏的牛棚).
样例数据
input
4 3 1
1 2
2 3
3 4
3
output
3
我们知道对于每一个损坏的点,跑不出去,周围的一个点一定是损坏的。
因此我们只需要把每一个损坏了的点的边上的v数组标记为1,再把自己标记为1,直接用bfs跑一遍遍历即可。
#include<bits/stdc++.h> using namespace std; int p,c,n,ans=0; int d[100000]; int v[100000]={}; int q[200000]={}; vector<int> a[100000]={}; inline void read(int &readnum) { int s=0,w=1;char c=getchar(); while (c<'0' || c>'9') {if (c=='-') w=-1; c=getchar();} while (c>='0' && c<='9') s=s*10+c-48,c=getchar(); readnum=s*w;return; } int main() { freopen("damage..in","r",stdin); freopen("damage..out","w",stdout); read(p),read(c),read(n); for (int i=1;i<=c;++i) { int x,y; read(x),read(y); a[x].push_back(y); a[y].push_back(x); } for (int i=1;i<=n;++i) { int k;read(k); for (int i=0;i<a[k].size();++i) v[a[k][i]]=1; } int h,t;t=h=1; memset(d,100,sizeof(d)); d[1]=0,v[1]=1,q[1]=1; while (h<=t) { int p=q[h++]; for (int i=0;i<a[p].size();++i) { int np=a[p][i]; if (v[np]) continue; d[np]=d[p]+1,v[np]=1,q[++t]=np; } } for (int i=1;i<=p;++i) if (d[i]>1e6) ans++; cout<<ans<<endl; return 0; }