zoj D friends (脑洞+队列)

106 篇文章 0 订阅
13 篇文章 0 订阅

题意:

有一群人,给出一些朋友关系,如果两个人有不少于k个共同朋友,那么他们也能成为朋友,问有多少人能成为新朋友


解题思路:

设num[i][j]记录i和j之间有多少个共同朋友,我们去枚举每个人,将每个人的所有朋友xi,num[x[i]][x[i+1]]++,最后去判断有多少个num[i][j]>=k,用队列去记录,让他们成为朋友,然后再把队列里记录的这些新朋友相关的num[i][j]++,再去判断是否有新朋友,加入到队列中,知道队列为空,答案就是队列的大小。


ps:to myself,队列记录的是边,边的数量是点的数量的平方,所以数组相应要开大。忘了这点看了一小时代码也没找出错。。


代码:


#include <bits/stdc++.h>
using namespace std;
int fri[105][105];
struct p
{
	int x;
	int y;
}que[10523];
int x[105];
int y[105];
int num[105][105];
int top;
int book[105][105];
int main()
{
   int t;
   cin>>t;
   while(t--)
   {
     int n, m, q;
     top=0;
     scanf("%d %d %d", &n, &m, &q);
     int a, b, i, j;
     memset(fri, 0, sizeof(fri));
     memset(book, 0, sizeof(book));
     memset(num, 0, sizeof(num));
     for(i=0; i<m; i++)
     {
	scanf("%d %d", &a, &b);
	x[i]=a;
	y[i]=b;
	fri[a][b]=1;
	fri[b][a]=1;
     }
     int k;
     for(i=0; i<n; i++)
     {
	 for(j=0; j<n; j++)
	 {
	   if(fri[i][j])
	   {
	     for(k=j+1; k<n; k++)
	     {
	         if(fri[i][k])num[j][k]++;
		 
	     }
	   }
	 }	 
     }
     int head, tail;
     head=tail=0;
     for(i=0; i<n; i++)
     {
	for(j=i+1; j<n; j++)
	{
	   if(num[i][j]>=q && fri[i][j]==0)que[tail].x=i, que[tail++].y=j, book[i][j]=book[j][i]=1, fri[j][i]=fri[i][j]=1;
	}
     }
 //    printf("%d\n", tail);
     while(head<tail)
     {
	int a, b;
	a=que[head].x;
	b=que[head].y;
//	printf("%d %d\n", a, b);
	for(i=0; i<n; i++)
	{
	   if(i!=a && fri[a][i])
	   {
	       //printf("%d %d\n", i, a);	
	       k=min(b,i);
       	       j=max(b,i);
	        num[k][j]++;
		//if(k!=j && num[k][j]>=q && book[k][j]==0 && fri[k][j]==0)fri[k][j]=1, fri[j][k]=1, que[tail].x=k, que[tail++].y=j, book[k][j]=book[j][k]=1;	   
	        	
	   }
	   if(i!=b && fri[b][i])
	   {
		//printf("%d %d\n", i, b);
	       k=min(a,i);
       	       j=max(a,i);
	        num[k][j]++;
		//if(k!=j && num[k][j]>=q && book[k][j]==0 && fri[k][j]==0)fri[k][j]=fri[j][k]=1,que[tail].x=k, que[tail++].y=j, book[k][j]=book[j][k]=1;	   
	   }
	}
     for(i=0; i<n; i++)
     {
	for(j=i+1; j<n; j++)
	{
	   if(num[i][j]>=q && fri[i][j]==0)que[tail].x=i, que[tail++].y=j, book[i][j]=book[j][i]=1, fri[j][i]=fri[i][j]=1;
	}
     }
	head++;
     }
     printf("%d\n", tail);
   }
}


这是一个使用优先队列(priority queue)的题目,可以使用C++ STL中的优先队列来实现。 以下是样例代码: ```c++ #include <iostream> #include <queue> // 包含 priority_queue 头文件 using namespace std; int main() { int n; while (cin >> n) { priority_queue<int, vector<int>, greater<int>> pq; // 定义小根堆 for (int i = 0; i < n; i++) { int x; cin >> x; pq.push(x); // 将元素加入优先队列 } int ans = 0; while (pq.size() > 1) { // 只要队列中还有两个及以上元素 int a = pq.top(); pq.pop(); int b = pq.top(); pq.pop(); ans += a + b; pq.push(a + b); // 新元素入队 } cout << ans << endl; } return 0; } ``` 在这个代码中,我们使用了C++ STL中的优先队列 `priority_queue`,它有三个模板参数: - `int`:表示队列中存储的元素类型是 `int`。 - `vector<int>`:表示队列内部使用 `vector` 作为基础容器。 - `greater<int>`:表示使用小根堆来存储元素。 在主函数中,我们首先读入元素,然后将它们加入到优先队列中。接着,我们依次取出队列中的两个最小元素,将它们相加并累加到答案中,然后将它们的和作为新元素加入到队列中。最后,当队列中只剩下一个元素时,输出答案。 需要注意的是,在使用小根堆时,我们要将模板参数 `greater<int>` 作为第三个参数传递给 `priority_queue`。如果不指定第三个参数,则默认使用大根堆。 另外,这里使用了 `while (cin >> n)` 的方式来不断读入测试用例,直到遇到输入结束符为止(比如EOF或者Ctrl+Z)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值