week8 C-班长竞选

题意

大学班级选班长,N 个同学均可以发表意见 若意见为 A B 则表示 A 认为 B 合适,意见具有传递性,即 A 认为 B 合适,B 认为 C 合适,则 A 也认为 C 合适 勤劳的 TT 收集了M条意见,想要知道最高票数,并给出一份候选人名单,即所有得票最多的同学,你能帮帮他吗?

Input

本题有多组数据。第一行 T 表示数据组数。每组数据开始有两个整数 N 和 M (2 <= n <= 5000, 0 <m <= 30000),接下来有 M 行包含两个整数 A 和 B(A != B) 表示 A 认为 B 合适。

Output

对于每组数据,第一行输出 “Case x: ”,x 表示数据的编号,从1开始,紧跟着是最高的票数。 接下来一行输出得票最多的同学的编号,用空格隔开,不忽略行末空格!

Sample Input

2
4 3
3 2
2 0
2 1
3 3
1 0
2 1
0 2

Sample Output

Case 1: 2
0 1
Case 2: 2
0 1 2

思路

本题考察强连通分量,采用kosaraju算法来找到所有的强连通分量
在存图的时候不仅要存原图,还要存反图,为了从DFS逆后序序列中进行反图DFS时确定出所有的SCC
首先经过一次DFS找到DFS的后序序列
然后将后序序列反向进行反图的DFS,此时由起点到达的所有点构成一个SCC
统计每个SCC的中的人数存到num数组中
之后再对原图进行一次DFS,确定所有能到达某一个SCC的所有SCC存入pre数组中
之后找到出度为0的点a(出度为0的人,支持他的人数最多),对于此点所在的SCC i,tmp数组存储支持他的人数,temp[a]+=num[i]-1
对于pre[i]中的SCC j:temp[a]+=num[j]
最后统计出得票最高的票数 ma,再将票数为ma的人的编号全部输出即可

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int maxn=5100;
int n,c[maxn],dfn[maxn],vis[maxn],dcnt,scnt,num[maxn],n1[maxn];
//dcnt-dfs序计数,scnt-scc计数
//dfn[i]-dfs后序列中第i个数
//c[i]-i号节点所在scc编号
//num-票数,n1-每个scc的人数
vector<int> g1[maxn],g2[maxn],pre[maxn];//g1-原图,g2-反图,pre-到达此scc的scc序号
void dfs1(int x)
{
	vis[x]=1;
	for(int i=0;i<g1[x].size();i++)
		if(!vis[g1[x][i]])
			dfs1(g1[x][i]);
	dfn[++dcnt]=x;
}
void dfs2(int x)
{
	c[x]=scnt;
	for(int i=0;i<g2[x].size();i++)
		if(!c[g2[x][i]])
			dfs2(g2[x][i]);
}
void dfs3(int x)
{
	vis[x]=2;
	for(int i=0;i<g1[x].size();i++)
	{
		vector<int>::iterator find1=find(pre[c[g1[x][i]]].begin(),pre[c[g1[x][i]]].end(),c[x]);
		if(c[g1[x][i]]!=c[x]&&find1==pre[c[g1[x][i]]].end())
			pre[c[g1[x][i]]].push_back(c[x]);
		if(vis[g1[x][i]]!=2)
			dfs3(g1[x][i]);
	}
}
void nu(int tmp,int x,int vi[])
{
	for(int i=0;i<pre[x].size();i++)
	{
		if(!vi[pre[x][i]])
		{
			vi[pre[x][i]]=1;
			num[tmp]+=n1[pre[x][i]];
			nu(tmp,pre[x][i],vi);
		}
	}
}
void k()
{
	dcnt=scnt=0;
	memset(c,0,sizeof(c));
	memset(vis,0,sizeof(vis));
	memset(num,0,sizeof(num));
	for(int i=0;i<n;i++)
		if(!vis[i])
			dfs1(i);
	for(int i=n-1;i>=0;i--)
		if(!c[dfn[i]])
		{
			++scnt;
			dfs2(dfn[i]);
		}
	for(int i=0;i<n;i++)
		if(vis[i]!=2)
			dfs3(i);
}
int main()
{
	int t;
	scanf("%d",&t);
	for(int l=1;l<=t;l++)
	{

		int m;
		scanf("%d%d",&n,&m);
		for(int i=0;i<=n+4;i++)
		{
			g1[i].clear();
			g2[i].clear();
			pre[i].clear();
		}
		int a,b;
		while(m--)
		{
			scanf("%d%d",&a,&b);
			g1[a].push_back(b);
			g2[b].push_back(a);
		}
		k();
		memset(n1,0,sizeof(n1));
		for(int i=1;i<=scnt;i++)
			for(int j=0;j<n;j++)
				if(c[j]==i)
					n1[i]++;
		for(int i=0;i<n;i++)
		{
			num[i]+=n1[c[i]]-1;
			int vi[scnt];
			memset(vi,0,sizeof(vi));
			vi[c[i]]=1;
			nu(i,c[i],vi);
		}
		int ma=-1;
		for(int i=0;i<n;i++)
			ma=max(ma,num[i]);
		 printf("Case %d: %d\n", l, ma);
		int tmp[maxn],co=0;
		for(int i=0;i<n;i++)
			if(num[i]==ma)
				tmp[co++]=i;
		for(int i=0;i<co;i++)
		{
			if(i<co-1)
				printf("%d ",tmp[i]);
			else
				printf("%d",tmp[i]);
		}
		printf("\n");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
优秀班委选举系统 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace 优秀班委选举 { public partial class Form1 : Form { private ListBox listBox; public Form1() { InitializeComponent(); } public Form1(ListBox listBox) { InitializeComponent(); this.listBox = listBox; } private void button1_Click(object sender, EventArgs e) { if (listBox1.Items.Count > 0) { if (listBox1.SelectedItem == null) { MessageBox.Show("请先选择一个对象!"); } else { //获取左边listBox1中选中的内容 string cont = listBox1.SelectedItem.ToString(); //左边listBox1中删除选中的内容 listBox1.Items.Remove(cont); //把获得的内容加入到右边的listBox2中 listBox2.Items.Add(cont); } } } private void button2_Click(object sender, EventArgs e) { if (listBox2.Items.Count > 0) { if (listBox2.SelectedItem == null) { MessageBox.Show("请先选择一个对象!"); } else { //获取右边listBox2中选中的内容 string cont = listBox2.SelectedItem.ToString(); //右边listBox2中删除选中的内容 listBox2.Items.Remove(cont); //把获得的内容加入到左边的listBox1中 listBox1.Items.Add(cont); } } } //退出 private void button5_Click(object sender, EventArgs e) { Application.Exit(); } //显示结果 private void button4_Click(object sender, EventArgs e) { //传递listBox2到Form2窗口中 Form2 form2 = new Form2(listBox2); form2.Show(); } //修改名单 private void button3_Click(object sender, EventArgs e) { if (listBox2.SelectedItem == null) { MessageBox.Show("请先选择一个对象!"); } else { string cont = listBox2.SelectedItem.ToString(); int index = listBox2.SelectedIndex; Form3 form3 = new Form3(cont, index, listBox2); form3.Show(); this.Hide(); } } //加载窗口 private void Form1_Load(object sender, EventArgs e) { if (listBox != null) { foreach (string str in listBox.Items) { listBox2.Items.Add(str); } } } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值