SRM 608 DIV1 Middle - BigO (復習x)
問題
有向グラフが与えられる。
このうち、巨大な経路長Lを考え、そのLの場合の数がO(L^K)となるかを知りたい。
O(L^K)となるときはKを、そうでないときは-1を返す。
解き方
ある閉路に対して途中で分岐があるのであれば、経路長は2^Lに増え続けるため-1となる。
逆に、そうでない閉路が存在すれば答えは存在する。
ただし、閉路でない場合はLが巨大になりえないので、答えは0となる。
ある閉路からある閉路まで移動することができるとき、
最初の閉路でLのうちいくつかの道を作り、次の経路で残りの数を選べるのでL^1となる。
つまり、閉路間の最大距離がKとなることがわかる。
同じ閉路に属するノードはUNION-FIND木を用いて同じ集合とし、最後にUNION同士の最大距離を求めればよい。
コード
using namespace std;
#define all(c) (c).begin(),(c).end()
#define FORE(i,d,e) for(int i=d;i<e;i++)
#define FOR(i,s,e) for (int i = int(s); i != int(e); i++)
#define FORIT(i,c) for (typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define ISEQ(c) (c).begin(), (c).end()
int un=1000;
int urank[1000],uparent[1000];
int d[60][60],d2[60][60];
class BigO {
public:
void union_init(){
FORE(i,0,un){
uparent[i]=i;
urank[i]=0;
}
}
int union_find(int x){
return (uparent[x]==x) ? x : (uparent[x]=union_find(uparent[x]));
}
void union_unit(int x,int y){
x=union_find(x),y=union_find(y);
if(x==y)return;
if(urank[x]<urank[y])uparent[x]=y;
else{
uparent[y]=x;
if(urank[x]==urank[y])urank[x]++;
}
}
int minK(vector<string> graph) {
int n=graph.size();
int nloop[n];
memset(nloop,0,sizeof(nloop));
FORE(i,0,n)FORE(j,0,n)d[i][j]=(graph[i][j]=='Y');
FORE(k,0,n)FORE(i,0,n)FORE(j,0,n)d[i][j]|=d[i][k]&&d[k][j];
union_init();
FORE(i,0,n){
FORE(j,0,n)if(i!=j&&graph[i][j]=='Y'&&d[j][i])nloop[i]++,union_unit(i,j);
if(nloop[i]>1)return -1;
}
if(count(nloop,nloop+n,1)==0)return 0;
int ret=0;
memset(d2,0,sizeof(d2));
FORE(i,0,n)FORE(j,0,n)if(nloop[i]&&nloop[j]&&d[i][j]&&union_find(i)!=union_find(j)){
d2[union_find(i)][union_find(j)]=1;
}
FORE(t,0,n)FORE(k,0,n)FORE(i,0,n)FORE(j,0,n){
if(i!=j&&j!=k&&k!=i&&d2[i][k]&&d2[k][j])d2[i][j]=d2[i][k]+d2[k][j];
ret=max(ret,d2[i][j]);
}
return ret;
}
};
#define all(c) (c).begin(),(c).end()
#define FORE(i,d,e) for(int i=d;i<e;i++)
#define FOR(i,s,e) for (int i = int(s); i != int(e); i++)
#define FORIT(i,c) for (typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define ISEQ(c) (c).begin(), (c).end()
int un=1000;
int urank[1000],uparent[1000];
int d[60][60],d2[60][60];
class BigO {
public:
void union_init(){
FORE(i,0,un){
uparent[i]=i;
urank[i]=0;
}
}
int union_find(int x){
return (uparent[x]==x) ? x : (uparent[x]=union_find(uparent[x]));
}
void union_unit(int x,int y){
x=union_find(x),y=union_find(y);
if(x==y)return;
if(urank[x]<urank[y])uparent[x]=y;
else{
uparent[y]=x;
if(urank[x]==urank[y])urank[x]++;
}
}
int minK(vector<string> graph) {
int n=graph.size();
int nloop[n];
memset(nloop,0,sizeof(nloop));
FORE(i,0,n)FORE(j,0,n)d[i][j]=(graph[i][j]=='Y');
FORE(k,0,n)FORE(i,0,n)FORE(j,0,n)d[i][j]|=d[i][k]&&d[k][j];
union_init();
FORE(i,0,n){
FORE(j,0,n)if(i!=j&&graph[i][j]=='Y'&&d[j][i])nloop[i]++,union_unit(i,j);
if(nloop[i]>1)return -1;
}
if(count(nloop,nloop+n,1)==0)return 0;
int ret=0;
memset(d2,0,sizeof(d2));
FORE(i,0,n)FORE(j,0,n)if(nloop[i]&&nloop[j]&&d[i][j]&&union_find(i)!=union_find(j)){
d2[union_find(i)][union_find(j)]=1;
}
FORE(t,0,n)FORE(k,0,n)FORE(i,0,n)FORE(j,0,n){
if(i!=j&&j!=k&&k!=i&&d2[i][k]&&d2[k][j])d2[i][j]=d2[i][k]+d2[k][j];
ret=max(ret,d2[i][j]);
}
return ret;
}
};