1. 程式人生 > >hdu5638 拓撲入門

hdu5638 拓撲入門

題意就是給你一個有向無環圖,並且告訴你:你可以任意刪去k條邊,問在刪去k條邊後字典序最小的拓撲排序的和也就是如果最後得出的拓撲排序是4 3 2 1 5,那麼就應該輸出4*1+3*2+2*3+1*4+5*5結果,最後結果要對1e9+7取模

思路:其實就是把普通的入度為1進隊改為入隊<=k 入隊。

感覺這題資料有點水,貌似不需要判斷重邊。

程式碼:

#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
#include<set>
#include<cstring>

using namespace std;

const int mod = 1e9 + 7;
const int maxn = 1e5 + 10;
typedef long long ll;
typedef pair<int, int> pii;
int in[maxn];
int vis[maxn];
int n, m,k;
ll ans = 0;
vector<int>vec[maxn];

void solve()
{
		priority_queue<int, vector<int>, greater<int> >que;
		for (int i = 1; i <=n; i++)
				if (in[i] <= k)
				{
						que.push(i);
						vis[i] = 1;
				}
		int cnt = 1;
		while (!que.empty())
		{
				int t = que.top();
				que.pop();
				if (in[t] > k)//如果t的入度小於現在的k,那麼他就不能被算入本次的拓撲序列中。
				{
						vis[t] = 0;
						continue;
				}
				k -= in[t];
				(ans +=(ll)t*cnt%mod) %= mod;//這裡的(ll)很重要哦
				cnt++;
				for (int i = 0; i < vec[t].size(); i++)
				{
						int point = vec[t][i];
						in[point]--;
						if (in[point] <= k && vis[point] == 0)
						{
								que.push(point);
								vis[point] = 1;
						}
				}
		}
}

void ini()
{
		memset(vis, 0, sizeof(vis));
		memset(in, 0, sizeof(in));
		ans = 0;
		for (int i = 1; i <= n; i++)
				vec[i].clear();
}

void getmap()
{
		for (int i = 0; i < m; i++)
		{
				int a, b;
				scanf("%d %d", &a, &b);
				vec[a].push_back(b);
				in[b]++;
		}
}

int main()
{
		int t;
		scanf("%d", &t);
		while (t--)
		{
				scanf("%d %d %d", &n, &m,&k);
				ini();
				getmap();
				solve();
				cout << ans%mod << endl;
		}
	//	system("pause");
		return 0;
}