タイトル説明
あまり知られていないシェフは、その味のメニューのためにATMホテルに招待されています。推定1 Nのシーケンス番号、最高の推定数1品質料理を所定のハイからローへの料理としてホテルの品質に応じてN皿のために調製小さなホテルATM、。
お料理との味との問題のため、いくつかの料理は、他の料理の前に行われなければならない。具体的には、のようなMストリップの合計「私番の料理は 『しなければならない』 Jの作った料理の番号の前に」限定されたので、私たちがします<I、J>と略記制限。
さて、料理の最適な生産・シーケンスを見つけることを期待してホテルには、小規模Aは、高品質の料理を食べようとすることができます:
言い換えれば、
(1)制限のすべての前提条件では、皿1「可能」優先産生を、
(2)すべての制限を満たして、お皿1優先前提の下で行われ、第2の皿は、優先順位の生産を「試す」「してみてください」。
(3)優先度の低いコンテキストを「試す」、第3の料理「試み」の優先順位は第1、すべての制限を満たすために製造され、第2の皿
;(4)すべての制限を満たすため、1番と2番と3番の料理は、より低い優先順位のコンテキスト、4皿「試行」優先生を「試みます」。
(5)などがあります。
実施例1:4つの料理二限界の合計<3,1>、<4,1>、生産順序は3,4,1,2です。
実施例2:5皿二リミット<5,2>、<4,3>の合計は、製造指図は1,5,2,4,3です。
例えば、第1考慮1、限界があるため、<3,1>と<4,1>、わずか3及び4、及びに従って後の完成生産を行うためにので(3)、および4に「試みる」べきである3号2次最終生産順序は3,4,1,2で決定し、検討する。優先順位番号、現在は3コースの生産順序が3,4,1で決定することができるので。
実施例2では、まず、制限は反しない; 2 <5,2>限られたので、次の5 2を再生産作成する場合、次の検討、3次<4,3>制限検討します次の3 4再生産を生成するので、それは、最終的に注文1,5,2,4,3です。今、あなたは順序を作る最高の料理を見つける必要があります。ノーソリューション出力「不可能!」(引用符なしでは、最初の文字は小文字に残り、大文字)
入力形式
最初の行は、データセットの数を表す、正の整数Dです。次に、グループDのデータ。データの各セットに対して2つのスペースで区切られた正の整数N及びMの最初の行はそれぞれ、料理の数及び生産の制限のためにエントリの数を表します。次のM行は、各行2つの正の整数x、yは、制限を表す「Yに対するXなければならない号号皿皿作り」。(注:M制限限界と同じあってもよいです)
出力フォーマット
D出力ファイルには、N個の整数のラインだけが含まれている料理の最適な生産配列を表し、または「不可能!」(引用符なし)何の解決策を示していません。
3 5 4 5 4 5 3 4 2 3 2 3 3 1 2 2 3 3 1 5 2 5 2 4 3
1 5 3 4 2 インポッシブル! 1 5 2 4 3
説明/ヒント
サンプル[解説]
皿の前に1皿2皿調製皿3の製造に先立って2皿、請求項3に第2のデータセットは、先行しながら
皿ない溶液が得られ、いずれの場合にも満たすことは不可能である1つの産生を、。
データの100%N、M <= 100000、D <= 3を満たします。
ソリューション:
① 不可能な状況:ifとだけ閉ループがある場合もございます。
②设编号小的菜为,编号大的菜为b。我们想要a尽量往前靠,贪心很容易举出反例
如:4种菜肴,限制为<2,4><3,1>,那么字典序最小的是2,3,1,4,但题目要求的最优解是3,1,2,4。
③如果最后一个数字在合法范围内尽可能大,那么这样是绝对有利的。
因为如果设最后一个数字是x,那么除了x之外的所有数都不会被放到最后一个位置。
因此,最优解就是符合条件的排列中,反序列的字典序最大的排列。
反向跑拓扑。让b连向a,跑反图的拓扑。利用优先队列维护。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int N = 1e5 + 5;
int n, m, cnt, T, indeg[N], ans[N];
vector <int> edge[N];
void input() {
cin >> n >> m;
for(int i = 1, x, y;i <= m;i ++) {
cin >> x >> y;
edge[y].push_back(x); indeg[x] ++;
}
}
void topsort() {
priority_queue <int> q;
for(int i = 1;i <= n;i ++)
if(! indeg[i]) q.push(i);
while(! q.empty()) {
int tmp=q.top(); q.pop();
ans[++ cnt] = tmp;
// for(vector<int>::iterator it = edge[tmp].begin();it != edge[tmp].end();it ++) {
// indeg[*it]--; //迭代器大法好啊!!
// if(! indeg[*it]) q.push(*it);
// }
for(int i = 0;i < edge[tmp].size();i ++) {
int it = edge[tmp][i]; indeg[it] --;
if(! indeg[it]) q.push(it);
}
}
}
void output() {
if(cnt < n) { puts("Impossible!"); return; }
for(int i = n; i ;i --) cout << ans[i] << " "; cout << endl;
}
void clear() {
cnt = 0;
memset(ans, 0, sizeof(ans));
memset(indeg, 0, sizeof(indeg));
for(int i = 1;i <= n;i ++) edge[i].clear();
}
int main() {
cin >> T;
while(T --> 0) clear(), input(), topsort(), output();
//一时压行一时爽,一直压行一直爽~~~
return 0;
}