算法訓練 審美課

算法訓練 審美課  
時間限制:1.0s   內存限制:256.0MB
    
問題描述
  《審美的歷程》課上有n位學生,帥老師展示了m幅畫,其中有些是梵高的作品,另外的都出自五歲小朋友之手。老師請同學們分辨哪些畫的作者是梵高,但是老師自己並沒有答案,因爲這些畫看上去都像是小朋友畫的……老師只想知道,有多少對同學給出的答案完全相反,這樣他就可以用這個數據去揭穿披着皇帝新衣的抽象藝術了(支持帥老師^_^)。
  答案完全相反是指對每一幅畫的判斷都相反。
輸入格式
  第一行兩個數n和m,表示學生數和圖畫數;
  接下來是一個n*m的01矩陣A:
  如果aij=0,表示學生i覺得第j幅畫是小朋友畫的;
  如果aij=1,表示學生i覺得第j幅畫是梵高畫的。
輸出格式
  輸出一個數ans:表示有多少對同學的答案完全相反。
樣例輸入
3 2
1 0
0 1
1 0
樣例輸出
2
樣例說明
  同學1和同學2的答案完全相反;
  同學2和同學3的答案完全相反;
  所以答案是2。
數據規模和約定
  對於50%的數據:n<=1000;
  對於80%的數據:n<=10000;
  對於100%的數據:n<=50000,m<=20。*/

 

//1.運行超時,只得了50分 

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sca=new Scanner(System.in);
        int m,n,x=0;
        int a[][];
        
        m=sca.nextInt();
        n=sca.nextInt();
        
        a=new int [m][n];
        
       for(int i=0;i<m;i++) {
           for(int j=0;j<n;j++) {
             a[i][j]=sca.nextInt();  
           }
       }
       
       for(int i=0;i<m;i++) {
            
           for(int k=i+1;k<m;k++)
           for(int j=0;j<n;j++) {
               if(a[i][j]==a[k][j]) {
                   break;
               }
               else if(j==n-1) {
                   x++;
               }
           }
       }
        System.out.println(x);
        
    }
     
}

分析:直接用數組保存各個學生的評價結果 

思路:我用的直接暴力法,每一組依此比較可以快速得出比較簡單數據的結果

          當然,想的越少,所得的也越少。

 //2.下面是大佬做的100分

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map.Entry;
 
public class Main {
    private static Reader reader;
 
    public static void main(String[] args) {
        reader = new InputStreamReader(System.in);
        int n, m;
        n = getInt();
        m = getInt();
        HashMap<Integer, Integer> hm = new HashMap<>(n);
        for (int i = 0; i < n; ++i) {
            int num = 0, x = 0;
            for (int j = 0; j < m; j++) {
                x = getInt();
                num = (num << 1) + x;
            }
            hm.put(num, hm.containsKey(num) ? hm.get(num) + 1 : 1);
        }
        int sum = 0, maxn = (1 << m) - 1;
        for (Entry<Integer, Integer> entry : hm.entrySet()) {
            if (maxn / 2 < entry.getKey())
                continue;
            int key = entry.getKey() ^ maxn;
            if (hm.containsKey(key))
                sum += hm.get(key) * entry.getValue();
        }
        System.out.println(sum);
    }
 
    public static int getInt() {
        int res = 0, read;
        try {
            while ((read = reader.read()) != -1) {
                if (Character.isDigit(read)) {// 因爲全是非負數,不需要判斷負號‘-’,只要是數字就行
                    res = read - '0';
                    while ((read = reader.read()) != -1) {// 繼續得到能得到的數字
                        if (Character.isDigit(read)) {
                            res = res * 10 + (read - '0');
                        } else {
                            break;
                        }
                    }
                    break;
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return res;
    }
}

分析:0,1相反異或^即可。題目輸入數據很大,需要用字符流來讀寫數據。不然會超時。

思路:用二進制表示每位同學的回答。(m<=20;2^20 在int的範圍內)。相反的答案用二進制與m個1,1,1.....1(即2^m-1)的數maxn取異或即可。(如 01 == 1 ,10 == 2,2^3 == 1(異或),1^3 == 2 )。

提高效率:map遍歷可以取0~maxn/2即可。。設m個1,1,1.....1(即2^m-1)的數爲maxn,mid = maxn/2;  通過枚舉你會發現 maxn^x = maxn-x = y (x,y屬於[0,maxn]),(maxn與x逐位取異或 實際就是逐位做減法,因爲maxn全爲1(1>={0,1}),不存在減法借位的),如(111-010 = 101 = 111^010),則[0,mid]的一個數x與maxn取異的值y一定在(mid,maxn]中。如(maxn = 7, 7^0=7 - 0 = 7、7^1=7-1=6、7^2=7-2=5).如果你遍歷了map中的[0~mid]那麼後面的就不需要再遍歷了,因爲後面map中能與[0~mid]匹配的值肯定已經被匹配過了。此步驟可要可不要,不會影響實際的通過。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章