Task1蛮有趣
Task2暴力dp==听老师讲了什么前缀和愣是没想通暴力的dp为什么要前缀和。。如果有前缀和我的dp就是O(n)了。。
Task3有一些问题
比如为什么关于开关问题同一个区间不会反转两次,虽然理由很有道理,但是我理解不通。。智商不够。。
那么以后只好记结论了
最后一题放一下题目讲一下思路。
图染色
Description
给定一个n个点,m条边的无向图。每条边都有一种颜色,’R’或者’B’;
每次染色可以选择一个点,把与这个相连的边的颜色都翻转。
求最少选择几个点进行染色,使得所有边的颜色最后都相同!
Solution
这个标点有点鬼。。
反正大概知道是开关问题了,那就很简单了。
首先枚举每个联通块的颜色。
并查集搞一下就差不多了。
怎么都觉得自己是第一次敲影子并查集。
[源代码]:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
#define pb push_back
#define vec vector<int>
const int M=4e5+5;
struct node{int to;bool c;};
vector<node>G[M];
vec Nod;
int n,m,fa[M],cnt[M];
bool mark[M];
inline void rd(int &a){
a=0;char c;
while(c=getchar(),!isdigit(c));
do a=a*10+(c^48);
while(c=getchar(),isdigit(c));
}
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void Min(int &a,int b){if(a==-1||a>b)a=b;}
void dfs(int v,const bool clr){
mark[v]=1;
Nod.pb(v);
for(int i=0;i<G[v].size();++i){
node u=G[v][i];
if(u.c==clr){
int f1=find(v),f2=find(u.to);
if(f1!=f2){
fa[f2]=f1;
cnt[f1]+=cnt[f2];
}
f1=find(v+n),f2=find(u.to+n);
if(f1^f2){
fa[f2]=f1;
cnt[f1]+=cnt[f2];
}
}
else{
int f1=find(v),f2=find(u.to+n);
if(f1!=f2){
fa[f2]=f1;
cnt[f1]+=cnt[f2];
}
f1=find(v+n),f2=find(u.to);
if(f1!=f2){
fa[f2]=f1;
cnt[f1]+=cnt[f2];
}
}
if(!mark[u.to])dfs(u.to,clr);
}
}
int main(){
int size = 256 << 20; // 256MB
char *p = (char*)malloc(size) + size;
__asm__("movl %0, %%esp\n" :: "r"(p));
cin>>n>>m;
char s[2];
for(int i=1,a,b,c;i<=m;++i){
rd(a),rd(b);scanf("%s",s);c=s[0]=='B';
G[a].pb((node){b,(bool)c}),G[b].pb((node){a,(bool)c});
}
int ans1=0,ans2=0;
for(int i=1;i<=n;++i)fa[i]=i,fa[i+n]=n+i,cnt[i]=1;
for(int i=1;i<=n;++i)
if(!mark[i]){
Nod.clear();
int res1=-1;
dfs(i,0);
int ct=0;
for(int j=0;j<Nod.size();++j){
if(Nod[j]==fa[Nod[j]])++ct;
if(Nod[j]+n==fa[Nod[j]]+n)++ct;
}
if(ct==1)res1=M;
else{
for(int j=0;j<Nod.size();++j){
int v=Nod[j];
if(fa[v]==v)Min(res1,cnt[v]);
if(fa[v+n]==v+n)Min(res1,cnt[v+n]);
fa[v]=v,fa[v+n]=v+n;
cnt[v]=1,cnt[v+n]=0;
mark[v]=0;
}
}
Nod.clear();
dfs(i,1);
int res2=-1;
ct=0;
for(int j=0;j<Nod.size();++j){
if(Nod[j]==fa[Nod[j]])++ct;
if(Nod[j]+n==fa[Nod[j]]+n)++ct;
}
if(ct==1)res2=M;
else{
for(int j=0;j<Nod.size();++j){
int v=Nod[j];
if(fa[v]==v)Min(res2,cnt[v]);
if(fa[v+n]==n+v)Min(res2,cnt[v+n]);
}
}
ans1+=res1;
ans2+=res2;
}
cout<<min(ans1,ans2)<<endl;
return 0;
}
代码略长,略丑。。但是思路很简单咯。