<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="cpp"><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">题目传送门在<a target=_blank href="http://soj.me/show_problem.php?pid=1424" target="_blank">此</a></span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">给定一组工资大小的限制条件,求出能不能有一个满足所有要求的工资方案,这个问题可以简化为求一个图的拓扑排序,但是更严格,根据题目要求,拓扑排序中级数相同的点工资数是一样的,所以不能简单地将一个个点拿出来。我们需要每一次循环将所有相同级别的点在一次循环中全部删除。</span>
发现自己写的代码风格很冗余,经常有多余的行和变量= =
现在问题来了,一开始我的做法是在邻接矩阵中,每个节点都有一个对应的指向它的所有节点的vector,每次删除一个节点,就遍历一次找出这个节点所指向的那些节点,把它从对应的vector里面erase掉,实验证明这无论对于这道题还是平时应用都是个傻逼办法。
简单地办法如下,弄一个对应矩阵,记录每个节点的入度,每个节点都有一个对应它指向的所有节点的vector,每次删一个节点,只需要遍历一遍这个vector,把对应节点的入度减1就行了你个傻逼。
代码如下:
#include <cstdio>
#include <cstring>
#include <vector>
#define SIZE 10002
using namespace std;
struct node {
vector<int> out;
};
int main() {
int n, m;
scanf("%d%d", &n, &m);
node graph[SIZE];
int degree[SIZE];
for (int i = 0; i < n; ++i)
degree[i] = 0;
for (int i = 0; i < m; ++i) {
int a, b;
scanf("%d%d", &a, &b);
graph[b - 1].out.push_back(a);
degree[a - 1]++;
}
int k = 0;//record the finished num;
int cur = 100;
int total = 0;
bool deleted[SIZE];
for (int i = 0; i < n; ++i)
deleted[i] = false;
while (k < n) {
vector<int> toBeDel;
for (int i = 0; i < n; ++i) {
if (!deleted[i] && degree[i] == 0) {
toBeDel.push_back(i);
}
}
if (toBeDel.empty()) {
break;
} else {
vector<int>::iterator temp;
for (temp = toBeDel.begin(); temp != toBeDel.end(); ++temp) {
printf("delete %d\n", (*temp + 1));
k++;
deleted[*temp] = true;
total += cur;
vector<int>::iterator it;
for (it = graph[*temp].out.begin(); it != graph[*temp].out.end(); ++it) {
degree[*it - 1]--;
}
}
cur++;
}
}
if (k == n) {
printf("%d\n", total);
} else {
printf("Poor Xed\n");
}
return 0;
}