选课(二分匹配)
Poj1649 COURSES
一共有N个学生跟P门课程一个学生可以任意选一 门或多门课,你需写一个程序,判断给定的输入是否可以满足以下条件。
1.每个学生选的都是不同的课(即不能有两个学生选同一门课)
2.即P门课都被成功选过
注意:是课程匹配的学生,学生没课上没事。
输入
第一行一个T代表T(T ≤ 10)组数据
对于每组测试样例,先输入两个整数P, N(P课程数 N学生数)。
接着p行:第i行代表第i门课程,首先一个数字k代表对课程i感兴趣的学生的个数,接下来是k个对这门课感兴趣的同学的编号。0 < P ≤ 500 0 < n ≤ 500。最大边数不超过1000.
输出
若能满足上述要求输出YES否则输出NO。
样例输入
2
3 3
3 1 2 3
2 1 2
1 1
3 3
2 1 3
2 1 3
1 1
样例输出
YES
NO
//二分匹配(完备匹配)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 5;
const int maxm = 500 + 5;
int un,vn;
int g[maxn][maxn];
int linker[maxn];
bool used[maxm];
bool dfs(int u){
for(int v=1;v<=vn;v++){
if(g[u][v]&&!used[v]){
used[v]=true;
if(linker[v]==-1||dfs(linker[v])){
linker[v]=u;
return true;
}
}
}
return false;
}
int hungary(){
int res = 0;
memset(linker,-1,sizeof linker);
for(int u=1;u<=un;u++){
memset(used,false,sizeof used);
if(dfs(u)) res++;
}
return res;
}
int main(){
int t,k,l;
cin>>t;
while(t--){
memset(g,0,sizeof g);
cin>>vn>>un;
for(int i=1;i<=vn;i++){
cin>>k;
for(int j=1;j<=k;j++){
cin>>l;
g[l][i]=1;
}
}
if(hungary()==vn)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
守卫城镇(最小点覆盖)
题目描述
边边喜欢玩电脑游戏,特别是战略游戏,但有时他无法找到解决方案,速度不够快,那么他很伤心。现在,他有以下的问题。他必须捍卫一个中世纪的城市,城市间的所有道路刚好形成了一颗以城市为结点以城市间的路为边的树。为了节省士兵的个数且使他们可以观察到所有的路(如果两个城镇间有路则士兵可以观测到),他打算为尽可能少的城镇中派遣观察士兵(每个城镇一位士兵),使得这些士兵可以观测到所有路的情况,问你最少需要多少名士兵。你能帮助他吗?
输入
输入包含多组测试样例。
对于每组测试样例,输入第一行包含一个数字n(n ≤ 1000)表示结点的个数。
接下来n行,对于每行,第一个数字表示结点u,第二个数字表示结点u的领边条数m,接下来m个数字表示与结点u相连结点的编号。保证边数小于10000。
输出
输出一个数字表示最小士兵数目。
样例输入
4
0 1 1
1 2 2 3
2 0
3 0
5
3 3 1 4 2
1 1 0
2 0
0 0
4 0
样例输出
1
2
//最小点匹配
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 5;
const int maxm = 10000 + 5;
int pre[maxn];
bool visit[maxn];
int newpos[maxn];
int now;
struct Edge{
int to,next;
}edge[maxm];
int cnt,head[maxn];
void init(){
memset(head,-1,sizeof head);
cnt=0;
}
void addedge(int u,int v){
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int x){
newpos[now++]=x;
for(int k=head[x];k!=-1;k=edge[k].next){
if(!visit[edge[k].to]){
visit[edge[k].to]=true;
pre[edge[k].to]=x;
dfs(edge[k].to);
}
}
}
int mvc(int n){
bool s[maxn]={0};
bool set[maxn]={0};
int ans = 0;
for(int i=n-1;i>=1;i--){
int t=newpos[i];
if(!s[t]&&!s[pre[t]]){
set[pre[t]]=true;
ans++;
s[t]=true;
s[pre[t]]=true;
}
}
return ans;
}
int main(){
int n,u,v,m;
while(cin>>n){
init();
for(int i=1;i<=n;i++){
cin>>u>>m;
for(int j=1;j<=m;j++){
cin>>v;
addedge(u,v);
addedge(v,u);
}
}
memset(visit,false,sizeof visit);
now=0;
visit[1]=true;
pre[1]=1;
dfs(1);
cout<<mvc(n)<<endl;
}
return 0;
}
奇迹暖暖(最大权匹配)
题目描述
梅拉抢走了绫罗的设计图,暖暖决定帮绫罗抢过来。于是梅拉和暖暖开始了搭配比赛。梅拉和暖暖各有n套衣服。由于暖暖是天才服装搭配师,且自带主角光环,又怎会输呢,(废话,输了你怎么通关啊)只不过暖暖为了让梅拉输的心服口服,决定狠狠虐梅拉一把。针对梅拉的n套衣服,暖暖的每套衣服i得分都比梅拉的任意一套衣服j得分高出score(ij),0<=score(ij)<100000。然而每比完一场,他们之后的比赛都不能再用这套的衣服了。所以对于n场比赛,求出暖暖最高能比梅拉高多少分?(至少为0)
输入
首行输入n(n<=300)
接下来n行,第i行表示暖暖的第i套衣服,每行n个数,第j个数表示暖暖第i套衣服比梅拉第j套衣服的分高多少分。
0<=score(ij)<100000
输出
输出一个整数,即最高高出多少分
样例输入
2
100 5
20 23
样例输出
123
//最大权匹配
#include<bits/stdc++.h>
using namespace std;
const int maxn = 300 + 5;
const int inf = 0x3f3f3f3f;
int nx, ny;
int g[maxn][maxn];
int linker[maxn], lx[maxn], ly[maxn];// y中个点匹配状态,x, y中的点标号
int slack[maxn];
bool visx[maxn], visy[maxn];
bool dfs(int x) {
visx[x] = true;
for(int y = 0; y < ny; y ++) {
if(visy[y]) continue;
int tmp = lx[x] + ly[y] - g[x][y];
if(tmp == 0) {
visy[y] = true;
if(linker[y] == -1 || dfs(linker[y])) {
linker[y] = x;
return true;
}
}
else if(slack[y] > tmp)
slack[y] = tmp;
}
return false;
}
int km() {
memset(linker, -1, sizeof linker);
memset(ly, 0, sizeof ly);
for(int i = 0; i < nx; i ++) {
lx[i] = -inf;
for(int j = 0; j < ny; j ++)
if(g[i][j] > lx[i])
lx[i] = g[i][j];
}
for(int x = 0; x < nx; x ++) {
for(int i = 0; i < ny; i ++)
slack[i] = inf;
while(true) {
memset(visx, false, sizeof visx);
memset(visy, false, sizeof visy);
if(dfs(x)) break;
int d = inf;
for(int i = 0; i < ny; i ++)
if(!visy[i] && d > slack[i])
d = slack[i];
for(int i = 0; i < nx; i ++)
if(visx[i])
lx[i] -= d;
for(int i = 0; i < ny; i ++) {
if(visy[i]) ly[i] += d;
else slack[i] -= d;
}
}
}
int res = 0;
for(int i = 0; i < ny; i ++)
if(linker[i] != -1)
res += g[linker[i]][i];
return res;
}
int main(){
int n;
cin>>n;
nx=ny=n;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>g[i][j];
}
}
cout<<km()<<endl;
return 0;
}