题目描述
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
#include
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
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;
}
题目描述
农夫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
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;
}