Size n tane 2 küçük harften oluşan stringler verilecek. Örneğin stringlerden biri "xy" olsun. Sizin dolduracağınız tabloda y, x'in bir sağında veya x'in bir altında olamaz.
Amacınız olabildiğince büyük bir kare tablo oluşturmak. Ayrıca bu kare çok büyük olabileceği için sizden max 20x20'lik bir kare istenmektedir.
Input Format
İlk satırda T:Test Case sayısı
Case'in ilk satırı n: Yasaklı string sayısı
Sonraki n satırda yasaklı stringler
Output Format
Kurallara uyan ve size'i max 20x20 olan bir kare tablo
Constraints
0 <= n <= 676
Input
2
628
aa
az
ba
bb
bc
...
by
ca
cb
cc
...
cy
...
...
ya
yb
yc
...
yy
za
zb
zc
...
zy
zz
2
aa
bb
Output
aw
wz
abababababababababab
babababababababababa
abababababababababab
babababababababababa
abababababababababab
babababababababababa
abababababababababab
babababababababababa
abababababababababab
babababababababababa
abababababababababab
babababababababababa
abababababababababab
babababababababababa
abababababababababab
babababababababababa
abababababababababab
babababababababababa
abababababababababab
babababababababababa
_______________________________
Linkler
Soru: http://codeforces.com/gym/100299 (K sorusu)
pdf: http://codeforces.com/gym/100299/attachments/download/2035/20132014-acm-icpc-central-european-regional-contest-cerc-13-en.pdf
Solutions: http://cerc.tcs.uj.edu.pl/2013/data/cerc2013solutions.pdf
_______________________________
Çözüm
Alfabenin 26 harfini birer node kabul edelim. Başlangıçta tüm nodelar arasında yol olan tam graph oluşturalım. Yasaklı stringler verildikçe yolları silelim. Oluşan graph'ımızda 2 farklı ihtimal vardır. Ya cycle buluncak ya da bulunmayacak. Bu 2 ihtimale göre farklı tablo oluşturma stratejileri izleyeceğiz.
Cycle varsa
Herhangi bir cycle'i kullanarak kolaylıkla 20x20'lik kare şeklinde bir tablo oluşturabiliriz. Sırasıyla "abc" diye bir cycle olduğunu düşünelim. İlk satırı "abcabc..." şeklinde oluştururuz ve her sonraki satırda ilk karakterimizi bir kaydırırız. 2.satırda "bcabca...", 3.satıtda "cabcab...", 4.satırda tekrar "abcabc..." olur. Peki cycle'i nasıl bulabiliriz?
Yanlış yaklaşım: Akla ilk gelen SCC yapmak oluyor ki kodlaması yapacağımız işe göre uzun. SCC kodlamanın diğer bir problemi elimize gelen SCC'nin sıralı bir şekilde olmaması. Örneğin cycle sırasıyla "abc" olsun. Bizim elimize "acb" şeklinde geçebilir. Bunun için ekstradan SCC'yi gezme sırasına göre sıralamamız gerekecek ki işimiz uzayacak ve kod bazen patlayacak.( Ben ve Kamil beceremedik :( )
Cycle bulma: Dfs'i kodlarken mark array'ini 0-1 şeklinde tutarız. Burada array'i 0-1-2 şeklinde tutacağız ve ek olarak Stack kullanacağız. Bir node'a ilk kez geldiysek node'un mark'ini 2 yapacağız ve stack'e atacağız. Fonksiyondan çıkarken mark'i 1 yapacağız ve stack'ten çekeceğiz. Eğer ki bu node'a önceden gelindiyse ve mark'i 2 ise bu node hala stack'tedir ve cycle vardır. Stack'ten bu node gelene kadar node'ları çekeriz ve her gelen node'ları cycle listemizin başına atarız. Bundan sonra geriye kalan tek şey tabloyu oluşturmak.
Cycle yoksa
DP kullanarak en uzun yolu buluruz. Amacımız KxK'lık kare oluşturmak ve bunu oluştururken 2*k-1 uzunluğunda bir yol bulmak. Eğer en uzun yolumuz 2*k uzunluğunda ise ilk veya son karakterini sileriz. Stratejimiz şöyle olacak... Tablonun ilk satırını en uzun yolumuzun ilk k karakteri ile dizelim. Ardından gelen her satırda ilk karakteri bir kaydıralım. Örneğin yolumuz "abcdef" ise uzunluk çift olduğu için son karakteri sileriz. "abcde" stringi kalır. İlk satır "abc", sonraki satır"bcd", ondan sonraki satır "cde" olur.
_______________________________
Kod
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <vector>
#include <stack>
#define pb push_back
using namespace std;
int T,n;
int dp[26];
int best[26];
int mark[26];
int ar[26][26];
vector<int>v;
stack<int>sta;
void Cycle()
{
int sz=v.size();
for(int i=0 ; i<20 ; i++)
{
int bas=i%sz;
for(int j=bas ; j<bas+20 ; j++)
printf("%c",v[j%sz]+'a');
printf("\n");
}
}
int f(int node)
{
if(v.size()) return dp[node];
if(mark[node]==1) return dp[node];
if(mark[node]==2)
{
while(sta.top()!=node)
{
v.pb(sta.top());
sta.pop();
}
v.pb(node);
reverse(v.begin(),v.end());
Cycle();
return dp[node];
}
dp[node]=1;
mark[node]=2;
sta.push(node);
for(int i=0 ; i<26 ; i++)
if(!ar[node][i])
{
int x=f(i)+1;
if(v.size()) break;
if(x>dp[node]) dp[node]=x,best[node]=i;
}
if(!sta.empty()) sta.pop();
mark[node]=1;
return dp[node];
}
void Reset()
{
v.clear();
memset(ar,0,sizeof(ar));
memset(mark,0,sizeof(mark));
while(!sta.empty()) sta.pop();
}
int main()
{
scanf("%d",&T);
while(T--)
{
Reset();
scanf("%d",&n);
for(int i=0 ; i<n ; i++)
{
char s[5];
scanf("%s",s);
ar[s[0]-'a'][s[1]-'a']=1;
}
int b1=0,b2=0;
for(int i=0 ; i<26 ; i++)
if(!mark[i])
{
int x=f(i);
if(x>b1) b1=x,b2=i;
}
if(v.size()) continue;
if(b1%2==0) b1--;
v.pb(b2);
for(int i=1,x=b2 ; i<b1 ; i++)
{
x=best[x];
v.pb(x);
}
for(int i=0 ; i<(b1+1)/2 ; i++,printf("\n"))
for(int j=0 ; j<(b1+1)/2 ; j++)
printf("%c",'a'+v[i+j]);
}
return 0;
}
Hiç yorum yok:
Yorum Gönder