1、给出一个二维数组$T[n][n],0\leq T[i][j] \leq n-1$。选出一个最小的集合$S$,使得对于任意的$x\in S,y\in S,T[x][y]\in S$.$1\leq n \leq 50$
思路:依次枚举每个元素$x$,作为$S$中开始选择的第一个元素。对于当前$S$中任意两个元素$i,j$,若$T[i][j]$不在$S$中,则将其加入$S$,然后继续扩展;若所有的$T[i][j]$都在$S$中,则结束扩展。每次扩展结束之后保存$|S|$的最小值。
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <stack>
using namespace std;
const int N=55;
int g[55][55];
int n;
int cal(const int x)
{
if(g[x][x]==x) return 1;
vector<int> s;
int h[N];
memset(h,0,sizeof(h));
s.push_back(x);
h[x]=1;
while(1)
{
int ok=1;
vector<int> ns=s;
for(int i=0;i<(int)s.size();++i) {
for(int j=0;j<(int)s.size();++j) {
int k=g[s[i]][s[j]];
if(!h[k]) {
h[k]=1;
ns.push_back(k);
ok=0;
}
}
}
if(ok) break;
s=ns;
}
return (int)s.size();
}
class MultiplicationTable2
{
public:
int minimalGoodSet(vector<int> a)
{
n=1;
while(n*n!=(int)a.size()) ++n;
for(int i=0;i<n;++i) for(int j=0;j<n;++j) g[i][j]=a[i*n+j];
int ans=n;
for(int i=0;i<n;++i)
{
int tmp=cal(i);
if(tmp<ans) ans=tmp;
}
return ans;
}
};
2、给出一个$n$个顶点$m$条边的无向图$G$。将边分为两个集合$P,Q$,使得当只存在$P$或者$Q$中的边时图$G$仍是联通的。$1\leq n \leq 10,1\leq m \leq 50$
思路:总的思路是搜索,分别枚举每一条边是在哪个集合中,进行如下的优化:
(1)使用并查集,当其中两个集合都联通时结束;当有一个集合联通时,直接判断剩下所有的边加入另一个集合能否使得另一个集合联通;
(2)如果当前剩下所有的边都加入到其中一个集合都不能使其联通时,结束搜索返回;
(3)当前边加入第一个集合使其联通分量减少时才进行加入的操作,否则不再继续搜索下去,而将其直接加入另一个集合。
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <stack>
using namespace std;
const int N=12;
int n,m;
vector<int> a,b;
struct UnionSet
{
int a[10];
int cnt;
void init()
{
for(int i=0;i<n;++i) a[i]=i;
cnt=0;
}
int get(int x)
{
if(a[x]!=x) a[x]=get(a[x]);
return a[x];
}
int up(int x,int y)
{
x=get(x);
y=get(y);
if(x==y) return 0;
if(x<y) a[y]=x;
else a[x]=y;
++cnt;
return 1;
}
int ok()
{
return cnt==n-1;
}
};
int check(UnionSet s,int id)
{
if(s.ok()) return 1;
if(id>=m) return 0;
for(int i=id;i<m&&!s.ok();++i)
{
s.up(a[i],b[i]);
}
return s.ok();
}
int dfs(int id,UnionSet s1,UnionSet s2)
{
if(s1.ok()&&s2.ok()) return 1;
if(s1.ok()) return check(s2,id);
if(s2.ok()) return check(s1,id);
if(!check(s1,id)||!check(s2,id)) return 0;
if(id>=m) return 0;
while(id<m)
{
if(s1.get(a[id])!=s1.get(b[id]))
{
UnionSet tmp=s1; tmp.up(a[id],b[id]);
if(dfs(id+1,tmp,s2)) return 1;
}
s2.up(a[id],b[id]);
++id;
}
return 0;
}
class FoxAirline2
{
public:
string isPossible(int nn,vector<int> aa,vector<int> bb)
{
n=nn;
a=aa;
b=bb;
m=(int)a.size();
UnionSet s1,s2; s1.init(); s2.init();
if(dfs(0,s1,s2)) return "Possible";
return "Impossible";
}
};