您的位置:首页 > 其它

集训队分组

2015-06-22 00:35 253 查看


Description

中南大学ACM的暑期集训马上就要开始了,这次集训会将全体N名集训队员(编号分别为1, 2, …, N)按集训选拔赛的排名分成两组,前K名队员分入A组,其余队员分入B组。

但现在助理教练CSGrandeur一不小心把集训选拔赛的排名弄丢了,而之前又没将A组和B组的人员确定出来,于是CSGrandeur打算问一下集训人员他们的名次各是怎样的,以此来确定一下A组的队员。

然而集训队员们都视名次如粪土,只是隐约记得某些人排在了自己的后面,最终反馈到CSGrandeur这里的一共有M条信息,每条信息都可以用一个二元组(x, y) (x!=y)表示,含义为第x名队员记得第y名队员的排名比自己的要靠后。

现在CSGrandeur想知道,根据这M条信息,是否可以确定出A组的队员呢?(默认所有集训队员反映的信息都是符合事实的。)

Input

输入包含多组测试数据。

对于每组测试数据,第一行包含三个正整数N (2<=N<=1000)、K (1<=K<=N)、M (1<=M<=10000),含义同上。接下来M行每行有两个正整数x、y (1<=x, y<=N且x!=y),分别描述了M条信息,对于每对x、y,均表示第x名队员记得第y名队员的排名比自己的要靠后。

Output

对于每组测试数据,如果可以确定出A组的队员,输出“YES”(不包括引号),否则输出“NO”(不包括引号)。

Sample Input

3 1 2 1 2 1 3 3 2 2 1 2 1 3

Sample Output

YES NO

建有向图,对每个结点bfs一遍,找出从它出发可以到达多少个结点,如果有n-k个结点在它之后,那它就是前k个了;
邻接矩阵会超时,要使用邻接表;
# include <iostream>

# include <cstdio>

# include <cstring>

# include <vector>
# define N 1005
using namespace std;
vector<int> g
;

char vis
;
int bfs(int u)

{

int i, cx, nx, ret;

int Q
, front, rear;
Q[1] = u;
memset(vis, 0, sizeof(vis));

vis[u] = 1;
front = 1;

rear = 2;
ret = 0;

while (front < rear)

{

cx = Q[front++];

for (i = 0; i < g[cx].size(); ++i)

{

nx = g[cx][i];

if (!vis[nx])

{

Q[rear++] = nx;

vis[nx] = 1;

++ret;

}

}

}
return ret;

}
int main()

{

int i, n, u, v, k, m, cnt;
while (~scanf("%d%d%d", &n, &k, &m))

{

for (i = 1; i <= n; ++i) g[i].clear();

for (i = 0; i < m; ++i)

{

scanf("%d%d", &u, &v);

g[u].push_back(v);

}

cnt = 0;

for(i = 1; i <= n; ++i)

{

if (bfs(i) >= n-k) ++cnt;

if (cnt >= k) break;

}

puts(cnt>=k ? "YES":"NO");

}
return 0;

}

2.。。。。
/*Accepted 880 kb 268 ms C++/ 1671 B 2012-07-29 17:08:30*/

#include<cstdio>

#include<cstring>

#include<cstdlib>
const int MAXN = 1 << 10;

const int MAXM = 10010;
int N, K, M, first[MAXN], e, next[MAXM], v[MAXM];

int topo[MAXN], cnt, vis[MAXN];
void addedge(int x, int y)

{

v[e] = y;

next[e] = first[x], first[x] = e ++;

}
void ReadGraph()

{

int i, x, y;

memset(first, -1, sizeof first);

e = 0;

for(i = 0; i < M; i ++)

{

scanf("%d%d", &x, &y);

addedge(x, y);

}

}
void dfs(int cur)

{

int i;

vis[cur] = 1;

for(i = first[cur]; i != -1; i = next[i])

if(!vis[v[i]])

dfs(v[i]);

topo[cnt --] = cur;

}
void toposort()

{

int i;

cnt = N;

memset(vis, 0, sizeof vis);

for(i = 1; i <= N; i ++)

if(!vis[i])

dfs(i);

}
void Search(int cur)

{

int i;

vis[cur] = 1;

for(i = first[cur]; i != -1; i = next[i])

if(!vis[v[i]])

Search(v[i]);

}
bool judge()

{

int i, j;

for(i = 1; i <= K; i ++)

{

memset(vis, 0, sizeof vis);

Search(topo[i]);

for(j = K + 1; j <= N; j ++)

if(!vis[topo[j]])

return false;

}

return true;

}
int main()

{

while(scanf("%d%d%d", &N, &K, &M) == 3)

{

ReadGraph();

toposort();

bool ok = judge();

if(ok)

printf("YES\n");

else

printf("NO\n");

}

return 0;

}

数学模型:给定n个未知数,m组关系,没组关系指出n个未知数中的2个的大小关系,例如A>B,求能否据此确定前k个数的集合?

一开始想到并查集,写了好几次都WA了,最后发现此题中的关系并不是等价关系。后来想到一个类似的题,那题也是给定n个未知数和一些大小关系,要求的是能否确定所有数的大小关系。那题是用拓扑排序做的。用拓扑排序的方法很容易找出一组符合条件的解,关键在于如何判断解的唯一性,如果解是唯一的,那么剩下的n-k个数一定在所选的k个数的后面,也就是从这所选的k个数(图中表示为结点)中任意一个出发,可以遍历到剩下的n-k个数。问题也就解决了。

#include <stdio.h>

#include <string.h>

#include <vector>

#define N 1001

using namespace std;

vector<int> g
;

int n,k,m,cnt,d
,a
,vis
,flag
;

void dfs(int u)

{

int i,v;

if(flag[u]==0 && vis[u]==0) cnt++;

vis[u]=1;

for(i=0;i<g[u].size();i++)

{

v=g[u][i];

if(!vis[v]) dfs(v);

}

}

int main()

{

int i,u,v;

while(~scanf("%d%d%d",&n,&k,&m))

{

for(i=1;i<=n;i++)

{

g[i].clear();

d[i]=0;

}

for(i=0;i<m;i++)

{

scanf("%d%d",&u,&v);

g[u].push_back(v);

d[v]++;

}

memset(flag,0,sizeof(flag));

cnt=0;

while(cnt<k)

{

for(u=1;u<=n && d[u];u++);

d[u]--;

a[cnt++]=u;

flag[u]=1;

for(i=0;i<g[u].size();i++)

{

v=g[u][i];

d[v]--;

}

}

for(i=0;i<k;i++)

{

u=a[i];

cnt=0;

memset(vis,0,sizeof(vis));

dfs(u);

if(cnt!=n-k) break;

}

if(i<k) puts("NO");

else puts("YES");

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: