贪心的总统

贪心的总统

1. 题目要求
★问题描述
水星人的选举大会即将召开,选举大会会在电视上直播,每个竞选者都有一次的发言机会,得票数最高的水星人成为下一届总统。随着时间的推移,观众会越来越少,所以所有的竞选者都想早发言,发言顺序由现任总统决定,所以有些竞选者就想破坏规则,贿赂现任总统,让现任总统一定要让他比他的强力竞争对手更早发言。现任总统全盘接受了贿赂,但他发现要选出一个发言顺序太难了,于是他决定让你帮他找出符合要求的发言顺序。
★数据输入
第一行有一个正整数n,表示有n位竞选者(n个竞选者从1到n编号)参与竞选
接下来有n行,每一行的第一位数 Li 表示第 i 位竞选者的强力竞争对手有 Li 个,接下来有Li个数,分别表示Li个强力竞争对手的编号。
n<=10000, 所有Li的和小于1000000
★数据输出
输出一种发言顺序满足所有贿赂者的要求,若有多种方案,输出字典序最小的一种。
★输入示例
3
0
1 1
2 1 2
★输出示例
3 2 1

2. 代码实现与分析
这道题的本质是靠拓扑排序,要保证字典序最小,所以用优先队列来解决,
第一版的代码使用的是邻接矩阵,空间不够直接爆炸。
所以第二版优化了邻接矩阵,使用bool变量来表示边的关系,空间会比int版的矩阵少上不少,所以过了。

#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=10010;
bool f[N][N];
int in_degree[N];
priority_queue<int,vector<int>,greater<int>  >q;//优先队列保证字典序最小 
const int INF =  0x3f3f3f3f;
void topological_sort_BFS(int n);//拓扑排序 
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin>>n;
	memset(f,0, sizeof(f));
	memset(in_degree, 0, sizeof(in_degree));
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		for(int j=1;j<=x;j++)
		{
			int t;
			cin>>t;
			f[i][t]=1;//边关系建立 
			in_degree[t]++;//入度+1 
		}
	}
	
	topological_sort_BFS(n);//拓扑排序 
	return 0;	
}
void topological_sort_BFS(int n)
{
	for(int i=1;i<=n;i++)
	{
		if (in_degree[i]==0)
		{
			q.push(i);
		}
	}
	while(!q.empty())
	{
		int u=q.top() ;
		q.pop();
		cout<<u<<" ";
		for(int i=1;i<=n;i++)
		{
			if(f[u][i]==1)
			{
			in_degree[i]=in_degree[i]-1;//入度-1 
			if (in_degree[i]==0)
			q.push(i);
			}
		}			
	}
}


第三版借助某位大佬的启发使用了链式前向星,优化了边的关系表示,空间复杂度降低了不少。

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
const int INF =0x3f3f3f3f;
const int MAX=1e5+5;
int head[MAX];
int cnt=0;
int inDegree[MAX];
priority_queue<int,vector<int>,greater<int>  >q;//优先队列保证字典序最小 
struct Edge
{
    int to,next;

}edge[MAX];
void add_edge(int u,int v)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}
int main()
{
    memset(head,-1,sizeof(head));
    int n,k,m,top;
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        cin>>k;
        for(int j=0;j<k;++j)
        {
            cin>>m;
            ++inDegree[m];
            add_edge(i,m);
        }

    }
    for(int i=1;i<=n;++i)
    {
        if(!inDegree[i])
        q.push(i);
    }
    while(!q.empty())
    {
        top=q.top();
        q.pop();
        cout<<top<<" ";
        for(int j=head[top];j!=-1;j=edge[j].next)
        {
            if(!(--inDegree[edge[j].to]))
            {
                q.push(edge[j].to);
            }
        }
    }
}
// 3
// 0
// 1 1
// 2 1 2
// 3 2 1


3. 总结
拓扑排序有两种实现方式,深度搜索和广度搜索实现,广度搜索比较好理解。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值