0 World Tour
Cicasso是一个著名的雕塑家。
现在他想去城市之间旅游,他是一个聪明的人,所以从一个城市到另一个城市他只会走最短路。他想游览全国的风景,所以他想走的路的总长度尽量长,但是经费有限,他只能去四个城市,而且这四个城市不能重复(在途中经过的城市不计算,例如 ,他要去的四个城市有上标,[1, 5, 2, 4],这样是合法的)
注意,道路是单向路,并且距离都为1。
先求出多源最短路,然后记录从每个城市出发的最长路和次长路、到达这个城市的最长路;
枚举两个连通的城市,用它们的前驱最长路、次长路和后继最长路、次长路更新答案
时间复杂度
O
(
n
2
)
O(n^2)
O(n2)
#include <cstdio>
#include <cstring>
using namespace std;
int n,m,ans,z,x,l,b;
int a[3004][3004],ls[3004],y[5004],ne[5004];
int d[3][3004],s[3][3004];
int v[10000000][3];
void bfs(){
int h=0,t=n;
for (int i=1;i<=n;i++)
v[i][0]=v[i][1]=i,a[i][i]=0;
while (h<t){
int e=v[++h][0],g=v[h][1],u=ls[v[h][1]];
while (u){
if (a[e][y[u]]==-1){
a[e][y[u]]=a[e][g]+1;
v[++t][0]=e,v[t][1]=y[u];
}
u=ne[u];
}
}
}
int main(){
scanf("%d%d",&n,&m);
memset(a,-1,sizeof a);
for (int j=1;j<=m;j++){
int u,v;
scanf("%d%d",&u,&v);
ne[j]=ls[u],y[j]=v,ls[u]=j;
}
for (int i=1;i<=n;i++) a[i][i]=0;
bfs();
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if ((i!=j)&&(a[i][j]!=-1)){
if (a[i][j]>a[d[0][j]][j]) d[1][j]=d[0][j],d[0][j]=i; else
if (a[i][j]>a[d[1][j]][j]) d[1][j]=i;
if (a[i][j]>a[i][s[0][i]]) s[1][i]=s[0][i],s[0][i]=j; else
if (a[i][j]>a[i][s[1][i]]) s[1][i]=j;
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if ((i!=j)&&(a[i][j]!=-1))
for (int c=0;c<=1;c++)
if ((j!=d[c][i]))
for (int e=0;e<=1;e++)
if ((i!=s[e][j])){
int u=d[c][i],v=s[e][j];
if (a[u][i]+a[i][j]+a[j][v]>ans)
ans=a[u][i]+a[i][j]+a[j][v],z=u,x=i,l=j,b=v;
}
printf("%d %d %d %d",z,x,l,b);
}
1 Graph Coloring
现在你有一张无向图包含n个节点m条边。最初,每一条边都是蓝色或者红色。每一次你可以将一个节点连接的所有边变色(从红变蓝,蓝变红)。
找到一种步数最小的方案,使得所有边的颜色相同。
总体思想是分别检查将边变为蓝色,或者红色,然后取最优方案即可。
每一个点最多改变一次,因为改变两次等于没有变化。因此我们要将点分为两 个集合S和T,分别代表要改变的点和不需要改变的点。如果我们现在要将所有边变 为红色,假设u和v之间有一条红色的边。如果要维持这种颜色,u和v要属于同一个 集合(S或者T)。另一方面,如果这条边是蓝色,那么 u和v就必须在两个不同的集 合。
于是问题简化为了0-1图染色问题,我们可以通过DFS或者BFS解决。因为图 不一定连通,所以有一些细节要注意,比如可能有多个连通块,此时取每个连通块最优的方案才是答案。
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e5+5;
int n,m,ans,ans1;
int tot,ls[N],ne[N*2],y[N*2],w[N*2];
int b[N];
queue <int> q;
int bfsred(){
int ans2=0,t=0;
for (int i=1;i<=n;i++)
if (b[i]==-1){
b[i]=t;int s1=0,s2=0;
while (!q.empty()) q.pop();
q.push(i);
while (!q.empty()){
int x=q.front(),u=ls[q.front()];q.pop();
while (u){
if (u==ls[i]) s1++;
if (b[y[u]]==-1){
if (w[u]==1) b[y[u]]=b[x];
if (w[u]==0) b[y[u]]=b[x]^1;
if (b[y[u]]==t) s1++; else s2++;
q.push(y[u]);
}else
if ((b[y[u]]==b[x])&&(w[u]==0)) return -1;else
if ((b[y[u]]!=b[x])&&(w[u]==1)) return -1;
u=ne[u];
}
}
t+=2;
ans2+=min(s1,s2);
}
return ans2;
}
int bfsblue(){
int ans2=0,t=0;
for (int i=1;i<=n;i++)
if (b[i]==-1){
b[i]=t;int s1=0,s2=0;
while (!q.empty()) q.pop();
q.push(i);
while (!q.empty()){
int x=q.front(),u=ls[q.front()];q.pop();
while (u){
if (u==ls[i]) s1++;
if (b[y[u]]==-1){
if (w[u]==0) b[y[u]]=b[x];
if (w[u]==1) b[y[u]]=b[x]^1;
if (b[y[u]]==t) s1++; else s2++;
q.push(y[u]);
}else
if ((b[y[u]]==b[x])&&(w[u]==1)) return -1;else
if ((b[y[u]]!=b[x])&&(w[u]==0)) return -1;
u=ne[u];
}
}
t+=2;
ans2+=min(s1,s2);
}
return ans2;
}
void set(int x,int r,int w1){
ne[++tot]=ls[x];ls[x]=tot;y[tot]=r;w[tot]=w1;
ne[++tot]=ls[r];ls[r]=tot;y[tot]=x;w[tot]=w1;
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
char ch;int x,r;
scanf("%d%d",&x,&r);
ch=getchar();ch=getchar();
if (ch=='B') set(x,r,0); else set(x,r,1);
}
memset(b,-1,sizeof b);
ans=bfsred();
memset(b,-1,sizeof b);
ans1=bfsblue();
if ((ans==-1)&&(ans1==-1)) printf("-1"); else
if (ans==-1) printf("%d",ans1);else
if (ans1==-1) printf("%d",ans);else
printf("%d",min(ans,ans1));
}
2 LCS again
现在有一个长度为n的串S,其中每一个字母都是前m个小写字母
计算有多少个不同的长度为n的T(其中T也是由前m个小写字母组成),并且S与T的LCS为n-1
LCS就是同时存在于S和T的最长子序列
与我生命等价的浮木
学习,你是
与我生命等价的浮木