Do You Know Your ABCs? 2
题意:
给你N个数( 4<=N<=7 ),分别是A、B、C、A+B、A+C、B+C、A+B+C中的N中;
已知1<=A<=B<=C,求根据给出的数,能确定多少种三元组(A.,B,C);
思路:
根据鸽巢原理,从给定的至少四个数中,一定能得出A+B+C,不是已经得到了就是可以从已知的某两个数中加出来,这样就得到了A+B+C;
同样根据鸽巢原理,我们用得到的A+B+C减去原来的 X 那么至少能得到A、B、C中的两个,这样我们从原来的N个数和A+B+C相减的数中的2N个数中暴力枚举A、B、C中的两个,第三个用A+B+C相减得到,再去判断原来的N个数是不是能够得到即可,用set<vector >来去重三元组。
int n,m,k,t;
int s[10];
map<int,int>vis;
vector<int>v;
set<vector<int> >ss;
vector<int>p;
vector<int>pp;
void check(int a,int b,int c){
v.clear();
v.push_back(a);v.push_back(b);v.push_back(c);
sort(v.begin(),v.end());
if(v[0]>=1){
vis.clear();
vis[a]=1;vis[b]=1;vis[c]=1;
vis[a+b]=1;vis[a+c]=1;vis[b+c]=1;
vis[a+b+c]=1;
int f=1;
for(int i=1;i<=n;i++){
if(!vis[s[i]])f=0;
}
if(f)ss.insert(v);
}
}
void solve(int x){
pp.clear();
for(int i=1;i<=n;i++){
pp.push_back(s[i]);
pp.push_back(x-s[i]);
}
for(int i=0;i<pp.size();i++){
for(int j=i+1;j<pp.size();j++){
check(pp[i],pp[j],x-pp[i]-pp[j]);
}
}
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
vis.clear();
p.clear();
ss.clear();
for(int i=1;i<=n;i++){
scanf("%d",&s[i]);
p.push_back(s[i]);
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++)p.push_back(s[i]+s[j]);
}
for(int i=0;i<p.size();i++){
solve(p[i]);
}
printf("%d\n",ss.size());
}
return 0;
}
第一次知道还可以 set< vector > 的,之前都想得是 用node来存储,但是结构体放到set里面要自定义哈希规则,可以这样也太方便了,直接定义vector,某个位置存储想要的值就可以了。·
Portals
题意:
给你n个顶点的图,每个顶点连接四条边,总共 2*n 条边;
这张图有两种移动方式:
第一、沿着边从一个顶点到另一个顶点;
第二、从这个顶点的第一条路到第二条路,或者相反。从这个顶点的第三条路到第四条路或者相反。
可以在顶点i上花费ci的费用令四条路重新排序;
求最小费用使得这张图连通。
思路:
已知这张图上有许多个闭环,可以在顶点上花费费用使得两个环合并,那么我们只用先使用并查集令原先的路合并,再用最小生成树即可。
int n,m;
int w[100060];
int s[5][100070];
int fa[400060];
int find(int x){
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
void join(int x,int y)
{
x=find(x),y=find(y);
if(x==y)return;
fa[y]=x;
}
struct node{
int from,to,cost;
}z[maxn];
vector<int>P[10*maxn];
int cnt=0;
bool cmp(node a,node b){
return a.cost<b.cost;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=4*n;i++)fa[i]=i;
for(int i=1;i<=n;i++){
scanf("%d%d%d%d%d",&w[i],&s[1][i],&s[2][i],&s[3][i],&s[4][i]);
join(s[1][i],s[2][i]);
join(s[4][i],s[3][i]);
}
for(int i=1;i<=n;i++){
int id1=s[1][i],id2=s[3][i];
if(find(id1)!=find(id2)){
++cnt;
z[cnt].from=find(id1);
z[cnt].to=find(id2);
z[cnt].cost=w[i];
}
}
sort(z+1,z+1+cnt,cmp);
int res=0;
for(int i=1;i<=cnt;i++){
if(find(z[i].from)!=find(z[i].to)){
res+=z[i].cost;
join(z[i].from,z[i].to);
}
}
printf("%d\n",res);
return 0;
}
原本想以城市为顶点,这样城市就要拆点了,挺麻烦的;
另一种思路就是合并道路,因为环的基本要素也是道路,最后 的生成树也是合并道路,从这个点出发,那就只需要合并道路就好了。