第10周训练总结

 由于这周最小生成树的任务完成的比较早,来主要复习一下。当然在总结一下二分查找。

最小生成树

1.关于最小生成树,更让人比较喜欢用Kruskal算法,即利用并查集来求最小生成树涉及主要算法是贪心

2.算法简单描写叙述

1).记Graph中有v个顶点。e个边

2).新建图Graphnew,Graphnew中拥有原图中同样的e个顶点,但没有边

3).将原图Graph中全部e个边按权值从小到大排序

4).循环:从权值最小的边開始遍历每条边 直至图Graph中全部的节点都在同一个连通分量中

                if 这条边连接的两个节点于图Graphnew中不在同一个连通分量中

                                         增加这条边到图Graphnew中

【题目描述】

有一张城市地图,图中的顶点为城市,无向边代表两个城市间的连通关系,边上的权为在这两个城市之间修建高速公路的造价,研究后发现,这个地图有一个特点,即任一对城市都是连通的。现在的问题是,要修建若干高速公路把所有城市联系起来,问如何设计可使得工程的总造价最少?
【输入】

n(城市数,1<≤n≤100)

e(边数)

以下e行,每行3个数i,j,wij,表示在城市i,j之间修建高速公路的造价。
【输出】

n-1行,每行为两个城市的序号,表明这两个城市间建一条高速公路。
 

int n,m,t;
int maxx,minn;
int i,j,k;
int flag,sum;
int fa[idata];
struct point
{
    int x,y,fee;
    const bool operator<(const point &b)
    const{
        return fee<b.fee;
    }
}a[idata];
int Find(int son)
{
    return son==fa[son]?son:fa[son]=Find(fa[son]);
}
void Union(int x,int y)
{
    x=Find(x),y=Find(y);
    if(x!=y)
        fa[y]=x;
}
 
int main()
{
    cin.tie(0);
    iostream::sync_with_stdio(false);
    while(cin>>n>>m)
    {
        int cnt=1;
        for(i=1;i<=m;i++)
        {
            int x,y,z;
            cin>>x>>y>>z;
            a[i].x=x;
            a[i].y=y;
            a[i].fee=z;
        }
        for(i=1;i<=n;i++) fa[i]=i;
        sort(a+1,a+1+m);
 
        for(i=1;i<=m;i++)
        {
            if(Find(a[i].x)!=Find(a[i].y))
            {
                Union(a[i].x,a[i].y);
                cout<<a[i].x<<" "<<a[i].y<<endl;
                flag++;
            }
            if(flag==n-1) break;
        }
    }
    return 0;
}

 因为主要熟悉一下模板,所以关于最小生成树就先介绍到这里

 二分查找

You are given a table consisting of n rows and m columns. Each cell of the table contains a number, 0 or 1. In one move we can choose some row of the table and cyclically shift its values either one cell to the left, or one cell to the right.

To cyclically shift a table row one cell to the right means to move the value of each cell, except for the last one, to the right neighboring cell, and to move the value of the last cell to the first cell. A cyclical shift of a row to the left is performed similarly, but in the other direction. For example, if we cyclically shift a row "00110" one cell to the right, we get a row "00011", but if we shift a row "00110" one cell to the left, we get a row "01100".

Determine the minimum number of moves needed to make some table column consist only of numbers 1.

Input

The first line contains two space-separated integers: n (1 ≤ n ≤ 100) — the number of rows in the table and m (1 ≤ m ≤ 104) — the number of columns in the table. Then n lines follow, each of them contains m characters "0" or "1": the j-th character of the i-th line describes the contents of the cell in the i-th row and in the j-th column of the table.

It is guaranteed that the description of the table contains no other characters besides "0" and "1".

Output

Print a single number: the minimum number of moves needed to get only numbers 1 in some column of the table. If this is impossible, print -1.

每一行都可以将其循环移位一下,问最少移位多少下,能够使得某一列都是1.

 题目思路:既然放到了二分搜索的题目里,就要考虑用二分的思想来考虑这个问题,

首先,如果有一行全是 0,那么直接输出 -1即可

对于每列计算把每一行中与此列最近的1移到此列的距离之和,然后取得最小值。然后可以去枚举每行两个 1 之间的位置到两个 1 的最小距离,然后将每列上的结果相加,取每列中的最小值

int n,m,t;
int i,j,k;
int cnt;
char ch[100+5][idata];
int pos[idata],dis[idata];

int main()
{
    cin.tie(0);
    iostream::sync_with_stdio(false);
    while(cin>>n>>m)
    {
        for(i=1;i<=n;i++){
            int f1=0;
            for(j=1;j<=m;j++){
                cin>>ch[i][j];
                if(ch[i][j]=='1'){
                    f1=1;
                }
            }
            if(f1==0){
                puts("-1");
                return 0;
            }
        }
        for(i=1;i<=n;i++){
            ms(pos,0),cnt=0;
            for(j=1;j<=m;j++){
                if(ch[i][j]=='1'){
                    pos[++cnt]=j;
                }
            }

            pos[++cnt]=pos[1]+m;
            for(j=1;j<cnt;j++){
                int mid=(pos[j]+pos[j+1])/2;
                for(k=pos[j];k<=pos[j+1];k++){
                    if(k<=mid){
                        dis[k%m]+=k-pos[j];
                    }
                    else{
                        dis[k%m]+=pos[j+1]-k;
                    }
                }
            }
        }

        int minn=0x7f7f7f7f;
        for(i=0;i<m;i++){
            minn=min(minn,dis[i]);
        }
        cout<<minn<<endl;
    }
    return 0;
}

 这几天做CF上的题越来越吃力了,题目有思路,但总是在细节上出岔子,一道题卡一个小时很正常,最近状态十分不嘉,晚上做题,想一会儿就感觉很累,emmmm,再努把力试试吧。

原创文章 410 获赞 16 访问量 3万+

猜你喜欢

转载自blog.csdn.net/C_Dreamy/article/details/105907818