题意 求可以删除K条边的DAG图的最大字典序的拓扑序列
思路 用优先队列维护入度小于等于K的点(注意入队后,不改变K),BFS,每次看堆顶元素i的入度是否小于等于当前的K,是则K减入度,删去到i的边,继续从i搜索,否则出队,继续看堆顶元素,重复上述步骤。继续搜到的点入度如果小于等于当前K则入队,注意维护是否入队的数组,不要重复入队~
注意点:(1)拓扑排序删边,不用真删,只要维护入度数组减一就行!!!
(2)就算是要真删,也可以用个is_del数组来表示这边是否真的删去,没必要从链表里删掉!
(3)我这题为了删去所有到一个点的边还写了个十字链表。。。真是二了。。。
不过可以当做今后的十字链表模板
(4)注意维护in_q这个数组,防止队中有重复元素
//#include <iostream>
#include <stdio.h>
#include <cmath>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdlib>
#include <map>
using namespace std;
#define I64_MAX 9223372036854775807
typedef long long ll;
const double pi=acos (-1.0);
const double eps=1e-8 ;
//const ll INF=(I64_MAX)/2;
//#pragma comment(linker, "/STACK:102400000,102400000")
const int inf=0x3f3f3f3f ;
#define maxx(a) memset(a, 0x3f, sizeof(a))
#define zero(a) memset(a, 0, sizeof(a))
#define FILL(a,b) memset(a, b, sizeof(a))
#define REP(i,a,b) for(i=a;i<b;i++)
#define rep(i,n) REP(i,0,n)
#define srep(i,n) for(i = 1;i <= n;i ++)
#define snuke(c,itr) for( __typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
#define MP make_pair
#define fi first
#define se second
typedef pair <int, int> PII;
typedef pair <ll, ll> PX;
typedef pair<int,ll> PIL;
#define maxn 100005
int n,m;
int ru[maxn];
//int chu[maxn];
priority_queue<int> q;
queue<int> q_print;
int in_q[maxn];
struct Edge{
int u,v,next,pre,rnext,rpre;
void set(int uu=0,int vv=0,int nextt=-1,int rnextt=-1,int pree=-1,int rpree=-1)
{
this->u = uu;
this->v = vv;
this->next = nextt;
this->pre = pree;
this->rnext = rnextt;
this->rpre = rpree;
}
}edge[maxn];
int g[maxn];
int rg[maxn];
void init()
{
memset(g,-1,sizeof(g));
memset(rg,-1,sizeof(rg));
// memset(chu,0,sizeof(chu));
memset(ru,0,sizeof(ru));
memset(in_q,0,sizeof(in_q));
while(q.size()>0)
q.pop();
while(q_print.size()>0)
q_print.pop();
}
void addEdge()
{
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
edge[i].set(u,v,g[u],rg[v]);
g[u] = i;
rg[v] = i;
if(edge[i].next != -1)
edge[edge[i].next].pre = i;
if(edge[i].rnext != -1)
edge[edge[i].rnext].rpre = i;
ru[v]++;
}
}
void del(int e)
{
if(edge[e].pre == -1)
{
g[edge[e].u] = edge[e].next;
}
else
{
edge[edge[e].pre].next = edge[e].next;
}
if(edge[e].rpre == -1)
{
rg[edge[e].v] = edge[e].rnext;
}
else
{
edge[edge[e].rpre].rnext = edge[e].rnext;
}
if(edge[e].next != -1)
{
edge[edge[e].next].pre = edge[e].pre;
}
if(edge[e].rnext != -1)
{
edge[edge[e].rnext].rpre = edge[e].rpre;
}
//return edge[e].next;
}
void delAll(int i)
{
for(int e=rg[i];e!=-1;e=edge[e].rnext)
{
del(e);
}
}
int main ()
{
#ifdef LOCAL
// freopen("E:\\input.txt" ,"r", stdin);
// freopen ("E:\\out.txt","w",stdout);
#endif
int i,j;
int K;
while(scanf("%d%d%d",&n,&m,&K)==3)
{
init();
addEdge();
for(i=n;i>=1;i--)
{
if(ru[i] <= K)
{
q.push(i);
in_q[i] = 1;
}
}
while(q.size() > 0)
{
int tmp;
while(1)
{
tmp = q.top();
q.pop();
in_q[tmp] = 0;
if(ru[tmp] <= K)
{
delAll(tmp);
K -= ru[tmp];
ru[tmp] = 0;
break;
}
}
q_print.push(tmp);
for(int e=g[tmp];e!=-1;e=edge[e].next)
{
ru[edge[e].v]--;
if(ru[edge[e].v] <= K && in_q[edge[e].v]==0)
{
q.push(edge[e].v);
in_q[edge[e].v] = 1;
}
del(e);
}
}
while(q_print.size()>1)
{
int tmp = q_print.front();
printf("%d ",tmp);
q_print.pop();
}
if(q_print.size() == 1)
{
int tmp = q_print.front();
printf("%d\n",tmp);
q_print.pop();
}
}
return 0;
}