问题描述
一张有向图的拓扑序列是图中点的一个排列,满足对于图中的每条有向边 (u→v) 从 u 到 v ,都满足 u 在排列中出现在 v 之前。 现在,DZY有一张有向无环图(DAG)。你要在最多删去 k 条边之后,求出字典序最大的拓扑序列。
输入描述
输入有多组数据。 ( TestCase≤5 ) 第一行,三个正整数 n,m,k(1≤n,m≤105,0≤k≤m) . 接下来 m 行,每行两个正整数 u,v(u≠v,1≤u,v≤n) , 代表一条有向边 (u→v) .
输出描述
对于每组测试数据,输出一行字典序最大的拓扑序列。
输入样例
5 5 2 1 2 4 5 2 4 3 4 2 3 3 2 0 1 2 1 3
输出样例
5 3 1 2 4 1 3 2
Hint
数据1. 删除(2->3),(4->5)两条边,可以得到字典序最大的拓扑序列:(5,3,1,2,4).
分析:刚看这题想了想,不就是拓扑排序+优先队列吗,只不过多了个删边。刚开始想的是,从最大的点开始删边,能删就删,删完边后再拓扑排序,写完一交果断WA。直到比赛结束,都没过。。。
后来想了想,应该在每一步拓扑排序的时候进行删边,如果存在一个点,将其入边全部删除以后,能改变当前拓扑排序的结果,即那个点比当前优先队列最大的元素还大,那么就将其入边都删掉,然后入队。交上去后超时了。。。因为我是顺序查找的最大元素,所以存在很多无用的查找。
最后我用一个set来保存,当前未入过队的元素,然后在里面找最大的点,查找的过程中如果发现某个点,已经入过队了,那么将其删除。终于AC- -。
一个简单的贪心+拓扑排序都没做出来,还是太弱了啊。。。。。。。。。。。。。
vector实现邻接表: 717MS
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstdio>
#include <vector>
#include <cctype>
#include <stack>
#include <queue>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 100005;
struct graph{
vector<int> list[maxn];
int in[maxn];
int n;//n个顶点
int m;//m条边
graph(){}
void clear(){
for(int i = 0; i <= n; i++){
list[i].clear();
in[i] = 0;
}
}
};
struct set_node{
int x;
set_node(int _x){
x = _x;
}
bool operator < (const set_node &b) const{
return x > b.x;
}
};
int k;
graph g;
int res[maxn];
void input(){
int u,v;
g.clear();
for(int i = 0; i < g.m; i++){
scanf("%d%d",&u,&v);
g.list[u].push_back(v);
g.in[v]++;
}
}
void solve(){
priority_queue<int> q;
set<set_node> s;
for(int i = 1; i <= g.n; i++){
if(g.in[i] == 0) q.push(i);
else s.insert(set_node(i));
}
for(int i = 1; i <= g.n; i++){//topsort
//
set<set_node>::iterator it;
if(k > 0)
for(it = s.begin(); it != s.end();){
int p = it->x;
if(p < q.top()) break;
if(g.in[p] > 0 && g.in[p] <= k){
k -= g.in[p];
g.in[p] = 0;
q.push(p);
break;
}
if(g.in[p] <= 0 ) {
set<set_node>::iterator itt = it;
it++;
s.erase(itt);
}
else it++;
}
int u = q.top(); q.pop();
g.in[u]--; res[i] = u;
for(int i = 0; i < g.list[u].size(); i++){
int v = g.list[u][i];
if(--g.in[v] == 0) q.push(v);
}
}//end of topsort
printf("%d",res[1]);
for(int i = 2; i <= g.n; i++) printf(" %d",res[i]);
printf("\n");
}
int main(){
while(scanf("%d%d%d",&g.n,&g.m,&k) == 3){
input();
solve();
}
return 0;
}
静态链实现邻接表:639MS
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstdio>
#include <vector>
#include <cctype>
#include <stack>
#include <queue>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 100005;
struct edge{
int v;
int next;
};
struct graph{
int list[maxn];
edge arc[maxn];
int cnt;
int in[maxn];
int n;//n个顶点
int m;//m条边
graph(){}
void clear(){
for(int i = 0; i <= n; i++){
list[i] = -1;
in[i] = 0;
}
cnt = 0;
}
void add(int u, int v){
arc[cnt].v = v;
arc[cnt].next = list[u];
list[u] = cnt;
cnt++;
}
};
struct set_node{
int x;
set_node(int _x){
x = _x;
}
bool operator < (const set_node &b) const{
return x > b.x;
}
};
int k;
graph g;
int res[maxn];
void input(){
int u,v;
g.clear();
for(int i = 0; i < g.m; i++){
scanf("%d%d",&u,&v);
g.add(u,v);
g.in[v]++;
}
}
void solve(){
priority_queue<int> q;
set<set_node> s;
for(int i = 1; i <= g.n; i++){
if(g.in[i] == 0) q.push(i);
else s.insert(set_node(i));
}
for(int i = 1; i <= g.n; i++){//topsort
//
set<set_node>::iterator it;
if(k > 0)
for(it = s.begin(); it != s.end();){
int p = it->x;
if(p < q.top()) break;
if(g.in[p] > 0 && g.in[p] <= k){
k -= g.in[p];
g.in[p] = 0;
q.push(p);
break;
}
if(g.in[p] <= 0 ) {
set<set_node>::iterator itt = it;
it++;
s.erase(itt);
}
else it++;
}
int u = q.top(); q.pop();
g.in[u]--; res[i] = u;
for(int i = g.list[u]; i != -1; i = g.arc[i].next){
int v = g.arc[i].v;
if(--g.in[v] == 0) q.push(v);
}
}//end of topsort
printf("%d",res[1]);
for(int i = 2; i <= g.n; i++) printf(" %d",res[i]);
printf("\n");
}
int main(){
while(scanf("%d%d%d",&g.n,&g.m,&k) == 3){
input();
solve();
}
return 0;
}