題目:https://odzkskevi.qnssl.com/889829830aaae78906451977015d8af0?v=1532315931
思路:
我發現我每次ac後就懶得寫思路了,所以這次一邊寫代碼一邊寫思路。
這題看了半天終於讀懂意思了。
這一段的意思相信大家都能讀懂。所以題目給我們的輸入是哪些字母互相之間有連線,這個連線的最長距離就是該字母的帶寬,所有字母帶寬的最大值就是該排列的帶寬。
比如樣例,A:FB;B:GC;D:GC;F:AGH;E:HD,如果我們按照ABCDEFGH來排列的話,那麼帶寬是5。而答案A B C F G D H E排列帶寬是3,顯然後者更優。而這題就是讓我們尋找最優解。
所以……要怎麼尋找。我是在刷紫書,所以看題時不小心就看到了劉汝佳的分析= =他說枚舉全排列,然後剪枝。那就試試唄……全排列的話,紫書前幾頁有一個STL裏的next_permutation()函數,在algorithm中。我們先把所有排列枚舉一下,然後分別計算他們的帶寬。因爲帶寬是要取所有結點之間距離的最大值,所以如果這兩個結點直接距離已經超過上一個排列的帶寬的話,我們就可以剪枝。
ok思路就到這裏……我去寫寫看。不成的話再改,反正也不是直播23333
-----------居然ac了,我還以爲會T。
這題輸入挺麻煩的,我用map裏面套set,本來是套vector的,但是vector會重複,所以用set比較好,並且set還自動排序。每一個結點對應的結點都放在它的set裏。嘛,看代碼就知道了。調用起來用迭代器就行。然後再用一個set來統計一共幾個字母。
代碼:
#include<iostream>
#include<algorithm>
#include<map>
#include<cstdio>
#include<string>
#include<cstring>
#include<set>
#include<cmath>
using namespace std;
#define INF 100000
map<int,set<int> >m;
set<int> s;
int ss[200];
int main()
{
char a[100];
char g[10];
while(scanf("%s",&a)&&a[0]!='#')
{
m.clear();
s.clear();
memset(ss,0,sizeof(ss));
memset(g,0,sizeof(g));
int cur=(int)a[0];
s.insert(a[0]);
for(int i=1;i<strlen(a);)
{
if(a[i]==':')i++;
else if(a[i]==';'){
i++;
s.insert(a[i]);
cur=(int)a[i];
i++;
}
else {m[cur].insert(a[i]);m[a[i]].insert(cur);s.insert(a[i]);i++;}
}
int k=0;
set<int>::iterator it;
for(it=s.begin();it!=s.end();it++)
{
ss[k]=*it;
k++;
}
sort(ss,ss+k);
int id[200];
int mmax=INF;
do{
memset(id,0,sizeof(id));
for(int i=0;i<k;i++){
id[ss[i]]=i;
}
int mo=-INF;
for(int i=0;i<k;i++){
int mm=-INF;
if(!m[ss[i]].empty()){
set<int>::iterator it;
for(it=m[ss[i]].begin();it!=m[ss[i]].end();it++)
{
mm=max(mm,abs(id[*it]-id[ss[i]]));
if(mm>=mmax)break;
}
}
mo=max(mo,mm);
if(mo>=mmax)break;
}
if(mo>=mmax)continue;
else {
mmax=mo;
for(int i=0;i<k;i++){
g[i]=(char)ss[i];
}
}
}while(next_permutation(ss,ss+k));
for(int i=0;i<k;i++){
cout<<g[i]<<" ";
}
cout<<"-> "<<mmax<<endl;
}
return 0;
}