解题报告 之 SGU242 Student‘s Morning
Description
One Monday morning after some very fun party N students woke up at the flat of one of them. Notice that it was a Monday morning and every student of that party needs to be in his university this day. But nobody wants to go to his university alone (there were
students from different universities). So, they decided to select from all universities only K of them to visit. Every selected university must be visited by at least two of the students. Every student has his own preference list of universities. It means,
if some university is in list of some student‘s preferred universities, this student can go to this university with some non-empty company of students. Notice, that some of students can stay at the flat and continue drinking "juices" and playing "games". For
example, student Shokman was to stay home (due to failed exam) with foreign student Chokman, who remained home because of runny nose.
In that problem there are no preferences between students, because if they have very fun party that already means that everyone of them prefers anybody from this company.
More formally, your task is, given numbers of students, selected universities and preference list of every student, to decide whether it is possible to visit all universities by at least two of students or no, and if it is possible you must output for each
university numbers of students, which have to go to it in one company. One student can‘t be in more than one company.
Input
First line of input file contains two numbers N and K (0<=K<=N<=200). Next N lines contain preference lists of each student. Every preference list is started by number of preferred universities followed by numbers of these universities.
Output
First line of output file must contain word "YES" (without quotes), if it possible to visit all universities, satisfying rules of that task or word "NO" (also without quotes) when it is impossible. In case of positive answer next K lines must contain lists
of students, who are going to corresponding university. First number in list of students must be a number of students in the list, followed by numbers of these students.
Sample test(s)
Input
4 2 1 1 2 1 2 1 2 2 1 2 3 2 2 1 2 2 1 2 2 1 2
Output
YES
2 1 2
2 3 4
NO
题目大意:好好一道水题你搞什么阅读理解! n个学生m个大学,每个学生有自己想去的大学,一个学生最多去一个大学(也可不去),每个大学至少要有两个人去,问是否是一种方案满足?如果有则输出任意一种满足的方案。
分析:有点像二分图匹配,然后用满流判断是否满足,再加上残余网络法输出方案。具体思路如下,超级源点与每个学生相连,负载为1,每个大学与超级汇点相连,负载为2。每个学生与要去的每所大学相连,负载都为1。然后跑最大流,如果满足max_flow==m*2,表示有解。此时扫描残余网络中与学生相连的每条边,如果不是与src相连的边且负载减小了(说明该学生去了该学校),则加入到对应大学的list中,最后输出list完事儿。另外此题内存稍小,所以必须控制好边数,大概是n*m多一点儿。
上代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; const int MAXN = 520; const int MAXM = 100000; const int INF = 0x3f3f3f3f; struct Edge { int from, to, cap, next, oricap; }; Edge edge[MAXM]; int head[MAXN]; int stu[405][405]; int level[MAXN]; int src, des, cnt; void addedge( int from, int to, int cap ) { edge[cnt].from = from; edge[cnt].to = to; edge[cnt].cap = cap; edge[cnt].oricap = cap; edge[cnt].next = head[from]; head[from] = cnt++; swap( from, to ); edge[cnt].from = from; edge[cnt].to = to; edge[cnt].cap = 0; edge[cnt].oricap = 0; edge[cnt].next = head[from]; head[from] = cnt++; } int bfs( ) { memset( level, -1, sizeof level ); queue<int> q; while (!q.empty( )) q.pop( ); level[src] = 0; q.push( src ); while (!q.empty( )) { int u = q.front( ); q.pop( ); for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (edge[i].cap > 0 && level[v] == -1) { level[v] = level[u] + 1; q.push( v ); } } } return level[des] != -1; } int dfs( int u, int f ) { if (u == des) return f; int tem; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (edge[i].cap > 0 && level[v] == level[u] + 1) { tem = dfs( v, min( f, edge[i].cap ) ); if (tem > 0) { edge[i].cap -= tem; edge[i ^ 1].cap += tem; return tem; } } } level[u] = -1; return 0; } int Dinic( ) { int ans = 0, tem; while (bfs( )) { while ((tem = dfs( src, INF )) > 0) { ans += tem; } } return ans; } int main( ) { int n, m; src = 0; des = 510; string str; while (cin >> n >> m) { memset( head, -1, sizeof head ); cnt = 0; for (int i = 1; i <= n; i++) { addedge( src, i, 1 ); int unum; cin >> unum; for (int j = 1; j <= unum; j++) { int u; cin >> u; addedge( i, u + 200, 1 ); } } for (int i = 1; i <= m; i++) { addedge( i + 200, des, 2 ); stu[i + 200][0] = 0; } if (Dinic( ) < m * 2) { cout << "NO" << endl; continue; } for (int i = 1; i <= n; i++) { for (int j = head[i]; j != -1; j = edge[j].next) { if (edge[j].to != src&&edge[j].oricap>edge[j].cap) { stu[edge[j].to][++stu[edge[j].to][0]] = i; } } } cout << "YES" << endl; for (int i = 1; i <= m; i++) { cout << stu[i + 200][0] << " "; for (int j = 1; j < stu[i + 200][0]; j++) { cout << stu[i + 200][j] << " "; } cout << stu[i + 200][stu[i + 200][0]] << endl; } } return 0; }
好吧。。。祝愿信息安全大赛成功,虽然我是抱大腿的哈哈哈哈哈哈哈哈BJ4.。。
解题报告 之 SGU242 Student's Morning